home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2008 February / PCWFEB08.iso / Software / Resources / Internet / WinHTTrack 3.41-2 / httrack-3.41-2.exe / {app} / src / htscore.c < prev    next >
Encoding:
C/C++ Source or Header  |  2006-09-10  |  113.9 KB  |  3,552 lines

  1. /* ------------------------------------------------------------ */
  2. /*
  3. HTTrack Website Copier, Offline Browser for Windows and Unix
  4. Copyright (C) Xavier Roche and other contributors
  5.  
  6. This program is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU General Public License
  8. as published by the Free Software Foundation; either version 2
  9. of the License, or any later version.
  10.  
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with this program; if not, write to the Free Software
  18. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  19.  
  20.  
  21. Important notes:
  22.  
  23. - We hereby ask people using this source NOT to use it in purpose of grabbing
  24. emails addresses, or collecting any other private information on persons.
  25. This would disgrace our work, and spoil the many hours we spent on it.
  26.  
  27.  
  28. Please visit our Website: http://www.httrack.com
  29. */
  30.  
  31.  
  32. /* ------------------------------------------------------------ */
  33. /* File: Main source                                            */
  34. /* Author: Xavier Roche                                         */
  35. /* ------------------------------------------------------------ */
  36.  
  37. /* Internal engine bytecode */
  38. #define HTS_INTERNAL_BYTECODE
  39.  
  40. #ifndef  _WIN32_WCE
  41. #include <fcntl.h>
  42. #endif
  43. #include <ctype.h>
  44.  
  45. /* File defs */
  46. #include "htscore.h"
  47.  
  48. /* specific definitions */
  49. #include "htsbase.h"
  50. #include "htsnet.h"
  51. #include "htsbauth.h"
  52. #include "htsmd5.h"
  53. #include "htsindex.h"
  54.  
  55. /* external modules */
  56. #include "htsmodules.h"
  57.  
  58. // htswrap_add
  59. #include "htswrap.h"
  60.  
  61. // parser
  62. #include "htsparse.h"
  63.  
  64. /* Cache */
  65. #include "htszlib.h"
  66.  
  67.  
  68. /* END specific definitions */
  69.  
  70. /* external modules */
  71. extern int hts_parse_externals(htsmoduleStruct* str);
  72. extern void htspe_init(void);
  73.  
  74. /* debug */
  75. #if DEBUG_SHOWTYPES
  76. char REG[32768]="\n";
  77. #endif
  78. #if NSDEBUG
  79. int nsocDEBUG=0;
  80. #endif
  81.  
  82. //
  83. #define _CLRSCR printf("\33[m\33[2J");
  84. #define _GOTOXY(X,Y) printf("\33[" X ";" Y "f");
  85.  
  86. #if DEBUG_CHECKINT
  87.  #define _CHECKINT_FAIL(a) printf("\n%s\n",a); fflush(stdout); exit(1);
  88.  #define _CHECKINT(obj_ptr,message) \
  89.    if (obj_ptr) {\
  90.      if (( * ((char*) (obj_ptr)) != 0) || ( * ((char*) (((char*) (obj_ptr)) + sizeof(*(obj_ptr))-1)) != 0)) {\
  91.        char msg[1100];\
  92.        if (( * ((char*) (obj_ptr)) != 0) && ( * ((char*) (((char*) (obj_ptr)) + sizeof(*(obj_ptr))-1)) != 0))\
  93.          sprintf(msg,"* PANIC: Integrity error (structure crushed)  in: %s",message);\
  94.        else if ( * ((char*) (obj_ptr)) != 0)\
  95.          sprintf(msg,"* PANIC: Integrity error (start of structure) in: %s",message);\
  96.        else\
  97.          sprintf(msg,"* PANIC: Integrity error (end of structure)   in: %s",message);\
  98.        _CHECKINT_FAIL(msg);\
  99.      }\
  100.    } else {\
  101.      char msg[1100];\
  102.      sprintf(msg,"* PANIC: NULL pointer in: %s",message);\
  103.      _CHECKINT_FAIL(msg);\
  104.    }
  105. #endif
  106.  
  107. #if DEBUG_HASH
  108.   // longest hash chain?
  109.   int longest_hash[3]={0,0,0},hashnumber=0;
  110. #endif
  111.  
  112. // DΘbut de httpmirror, routines annexes
  113.  
  114. // version 1 pour httpmirror
  115. // flusher si on doit lire peu α peu le fichier
  116. #define test_flush if (opt->flush) { fflush(opt->log); fflush(opt->log); }
  117.  
  118. // pour allΘger la syntaxe, des raccourcis sont crΘΘs
  119. #define urladr   (liens[ptr]->adr)
  120. #define urlfil   (liens[ptr]->fil)
  121. #define savename (liens[ptr]->sav)
  122. //#define level    (liens[ptr]->depth)
  123.  
  124. // au cas o∙ nous devons quitter rapidement xhttpmirror (plus de mΘmoire, etc)
  125. // note: partir de liens_max.. vers 0.. sinon erreur de violation de mΘmoire: les liens suivants
  126. // ne sont plus α nous.. agh! [dur celui-lα]
  127. #define HTMLCHECK_UNINIT { \
  128. if ( (opt->debug>0) && (opt->log!=NULL) ) { \
  129. HTS_LOG(opt,LOG_INFO); fprintf(opt->log,"engine: end"LF); \
  130. } \
  131. RUN_CALLBACK0(opt, end); \
  132. }
  133.  
  134. #define XH_extuninit do { \
  135.   int i; \
  136.   HTMLCHECK_UNINIT \
  137.   if (liens!=NULL) { \
  138.   for(i=lien_max-1;i>=0;i--) { \
  139.   if (liens[i]) { \
  140.   if (liens[i]->firstblock==1) { \
  141.   freet(liens[i]); \
  142.   liens[i]=NULL; \
  143.   } \
  144.   } \
  145.   } \
  146.   freet(liens); \
  147.   liens=NULL; \
  148.   } \
  149.   if (filters && filters[0]) { \
  150.   freet(filters[0]); filters[0]=NULL; \
  151.   } \
  152.   if (filters) { \
  153.   freet(filters); filters=NULL; \
  154.   } \
  155.   back_delete_all(opt,&cache,sback); \
  156.   back_free(&sback); \
  157.   checkrobots_free(&robots);\
  158.   if (cache.use) { freet(cache.use); cache.use=NULL; } \
  159.   if (cache.dat) { fclose(cache.dat); cache.dat=NULL; }  \
  160.   if (cache.ndx) { fclose(cache.ndx); cache.ndx=NULL; } \
  161.   if (cache.zipOutput) { \
  162.     zipClose(cache.zipOutput, "Created by HTTrack Website Copier/"HTTRACK_VERSION); \
  163.     cache.zipOutput = NULL; \
  164.   } \
  165.   if (cache.zipInput) { \
  166.     unzClose(cache.zipInput); \
  167.     cache.zipInput = NULL; \
  168.   } \
  169.   if (cache.olddat) { fclose(cache.olddat); cache.olddat=NULL; } \
  170.   if (cache.lst) { fclose(cache.lst); cache.lst=NULL; } \
  171.   if (cache.txt) { fclose(cache.txt); cache.txt=NULL; } \
  172.   if (opt->log) fflush(opt->log); \
  173.   if (opt->log) fflush(opt->log);\
  174.   if (makestat_fp) { fclose(makestat_fp); makestat_fp=NULL; } \
  175.   if (maketrack_fp){ fclose(maketrack_fp); maketrack_fp=NULL; } \
  176.   if (opt->accept_cookie) cookie_save(opt->cookie,fconcat(OPT_GET_BUFF(opt),StringBuff(opt->path_log),"cookies.txt")); \
  177.   if (makeindex_fp) { fclose(makeindex_fp); makeindex_fp=NULL; } \
  178.   if (cache_hashtable) { inthash_delete(&cache_hashtable); } \
  179.   if (cache_tests)     { inthash_delete(&cache_tests); } \
  180.   if (template_header) { freet(template_header); template_header=NULL; } \
  181.   if (template_body)   { freet(template_body); template_body=NULL; } \
  182.   if (template_footer) { freet(template_footer); template_footer=NULL; } \
  183.   clearCallbacks(&opt->state.callbacks); \
  184.   /*structcheck_init(-1);*/ \
  185. } while(0)
  186. #define XH_uninit do { XH_extuninit; if (r.adr) { freet(r.adr); r.adr=NULL; } } while(0)
  187.  
  188. // Enregistrement d'un lien:
  189. // on calcule la taille nΘcessaire: taille des 3 chaεnes α stocker (taille forcΘe paire, plus 2 octets de sΘcuritΘ)
  190. // puis on vΘrifie qu'on a assez de marge dans le buffer - sinon on en rΘalloue un autre
  191. // enfin on Θcrit α l'adresse courante du buffer, qu'on incrΘmente. on dΘcrΘmente la taille dispo d'autant ensuite
  192. // codebase: si non nul et si .class stockee on le note pour chemin primaire pour classes
  193. // FA,FS: former_adr et former_fil, lien original
  194. #define liens_record_sav_len(A) 
  195.  
  196. #define liens_record(A,F,S,FA,FF,NORM) { \
  197. int notecode=0; \
  198. size_t lienurl_len=((sizeof(lien_url)+HTS_ALIGN-1)/HTS_ALIGN)*HTS_ALIGN,\
  199.   adr_len=strlen(A),\
  200.   fil_len=strlen(F),\
  201.   sav_len=strlen(S),\
  202.   cod_len=0,\
  203.   former_adr_len=strlen(FA),\
  204.   former_fil_len=strlen(FF); \
  205. if (former_adr_len>0) {\
  206.   former_adr_len=(former_adr_len/HTS_ALIGN)*HTS_ALIGN+HTS_ALIGN*2; \
  207.   former_fil_len=(former_fil_len/HTS_ALIGN)*HTS_ALIGN+HTS_ALIGN*2; \
  208. } else former_adr_len=former_fil_len=0;\
  209. if (strlen(F)>6) if (strnotempty(codebase)) if (strfield(F+strlen(F)-6,".class")) { notecode=1; \
  210. cod_len=strlen(codebase); cod_len=(cod_len/HTS_ALIGN)*HTS_ALIGN+HTS_ALIGN*2; } \
  211. adr_len=(adr_len/HTS_ALIGN)*HTS_ALIGN+HTS_ALIGN*2; fil_len=(fil_len/HTS_ALIGN)*HTS_ALIGN+HTS_ALIGN*2; sav_len=(sav_len/HTS_ALIGN)*HTS_ALIGN+HTS_ALIGN*2; \
  212. if ((int) lien_size < (int) (adr_len+fil_len+sav_len+cod_len+former_adr_len+former_fil_len+lienurl_len)) { \
  213. lien_buffer=(char*) ((void*) calloct(add_tab_alloc,1)); \
  214. lien_size=add_tab_alloc; \
  215. if (lien_buffer!=NULL) { \
  216. liens[lien_tot]=(lien_url*) (void*) lien_buffer; lien_buffer+=lienurl_len; lien_size-=lienurl_len; \
  217. liens[lien_tot]->firstblock=1; \
  218. } \
  219. } else { \
  220. liens[lien_tot]=(lien_url*) (void*) lien_buffer; lien_buffer+=lienurl_len; lien_size-=lienurl_len; \
  221. liens[lien_tot]->firstblock=0; \
  222. } \
  223. if (liens[lien_tot]!=NULL) { \
  224. liens[lien_tot]->adr=lien_buffer; lien_buffer+=adr_len; lien_size-=adr_len; \
  225. liens[lien_tot]->fil=lien_buffer; lien_buffer+=fil_len; lien_size-=fil_len; \
  226. liens[lien_tot]->sav=lien_buffer; lien_buffer+=sav_len; lien_size-=sav_len; \
  227. liens[lien_tot]->cod=NULL; \
  228. if (notecode) { liens[lien_tot]->cod=lien_buffer; lien_buffer+=cod_len; lien_size-=cod_len; strcpybuff(liens[lien_tot]->cod,codebase); } \
  229. if (former_adr_len>0) {\
  230. liens[lien_tot]->former_adr=lien_buffer; lien_buffer+=former_adr_len; lien_size-=former_adr_len; \
  231. liens[lien_tot]->former_fil=lien_buffer; lien_buffer+=former_fil_len; lien_size-=former_fil_len; \
  232. strcpybuff(liens[lien_tot]->former_adr,FA); \
  233. strcpybuff(liens[lien_tot]->former_fil,FF); \
  234. }\
  235. strcpybuff(liens[lien_tot]->adr,A); \
  236. strcpybuff(liens[lien_tot]->fil,F); \
  237. strcpybuff(liens[lien_tot]->sav,S); \
  238. liens_record_sav_len(liens[lien_tot]); \
  239. hash_write(hashptr,lien_tot,NORM);  \
  240. } \
  241. }
  242.  
  243.  
  244. #define HT_INDEX_END do { \
  245. if (!makeindex_done) { \
  246. if (makeindex_fp) { \
  247.   char BIGSTK tempo[1024]; \
  248.   if (makeindex_links == 1) { \
  249.     sprintf(tempo,"<meta HTTP-EQUIV=\"Refresh\" CONTENT=\"0; URL=%s\">"CRLF,makeindex_firstlink); \
  250.   } else \
  251.     tempo[0]='\0'; \
  252.   fprintf(makeindex_fp,template_footer, \
  253.     "<!-- Mirror and index made by HTTrack Website Copier/"HTTRACK_VERSION" "HTTRACK_AFF_AUTHORS" -->", \
  254.     tempo \
  255.     ); \
  256.   fflush(makeindex_fp); \
  257.   fclose(makeindex_fp);  /* α ne pas oublier sinon on passe une nuit blanche */  \
  258.   makeindex_fp=NULL; \
  259.   usercommand(opt,0,NULL,fconcat(OPT_GET_BUFF(opt),StringBuff(opt->path_html),"index.html"),"","");  \
  260. } \
  261. } \
  262. makeindex_done=1;    /* ok c'est fait */  \
  263. } while(0)
  264.  
  265.  
  266.  
  267.  
  268. // DΘbut de httpmirror, robot
  269. // url1 peut Ωtre multiple
  270. int httpmirror(char* url1, httrackp* opt) {
  271.   char* primary=NULL;          // premiΦre page, contenant les liens α scanner
  272.   int lien_tot=0;              // nombre de liens pour le moment
  273.   lien_url** liens=NULL;       // les pointeurs sur les liens
  274.   hash_struct hash;            // systΦme de hachage, accΘlΦre la recherche dans les liens
  275.   hash_struct* hashptr = &hash;
  276.   t_cookie BIGSTK cookie;             // gestion des cookies
  277.   int lien_max=0;
  278.   size_t lien_size=0;        // octets restants dans buffer liens dispo
  279.   char* lien_buffer=NULL; // buffer liens actuel
  280.   int add_tab_alloc=256000;    // +256K de liens α chaque fois
  281.   //char* tab_alloc=NULL;
  282.   int ptr;             // pointeur actuel sur les liens
  283.   //
  284.   int numero_passe=0;  // deux passes pour html puis images
  285.   struct_back* sback=NULL;
  286.   htsblk BIGSTK r;            // retour de certaines fonctions
  287.   // pour les stats, nombre de fichiers & octets Θcrits
  288.   LLint stat_fragment=0;  // pour la fragmentation
  289.   //TStamp istat_timestart;   // dΘpart pour calcul instantannΘ
  290.   //
  291.   TStamp last_info_shell=0;
  292.   int info_shell=0;
  293.   // filtres
  294.   char** filters = NULL;
  295.   //int filter_max=0;
  296.   int filptr=0;
  297.   //
  298.   int makeindex_done=0;  // lorsque l'index sera fait
  299.   FILE* makeindex_fp=NULL;
  300.   int makeindex_links=0;
  301.   char BIGSTK makeindex_firstlink[HTS_URLMAXSIZE*2];
  302.   // statistiques (mode #Z)
  303.   FILE* makestat_fp=NULL;    // fichier de stats taux transfert
  304.   FILE* maketrack_fp=NULL;   // idem pour le tracking
  305.   TStamp makestat_time=0;    // attente (secondes)
  306.   LLint makestat_total=0;    // repΦre du nombre d'octets transfΘrΘs depuis denriΦre stat
  307.   int makestat_lnk=0;        // idem, pour le nombre de liens
  308.   //
  309.   char BIGSTK codebase[HTS_URLMAXSIZE*2];  // base pour applet java
  310.   char BIGSTK base[HTS_URLMAXSIZE*2];      // base pour les autres fichiers
  311.   //
  312.   cache_back BIGSTK cache;
  313.   robots_wizard BIGSTK robots;    // gestion robots.txt
  314.   inthash cache_hashtable=NULL;
  315.   inthash cache_tests=NULL;
  316.   int cache_hash_size=0;
  317.   //
  318.   char *template_header=NULL,*template_body=NULL,*template_footer=NULL;
  319.   //
  320.   codebase[0]='\0'; base[0]='\0';
  321.   //
  322.   cookie.auth.next=NULL;
  323.   cookie.auth.auth[0]=cookie.auth.prefix[0]='\0';
  324.   //
  325.  
  326.   // noter heure actuelle de dΘpart en secondes
  327.   memset(&HTS_STAT, 0, sizeof(HTS_STAT));
  328.   HTS_STAT.stat_timestart=time_local();
  329.   //istat_timestart=stat_timestart;
  330.   HTS_STAT.istat_timestart[0]=HTS_STAT.istat_timestart[1]=mtime_local();
  331.   /* reset stats */
  332.   HTS_STAT.HTS_TOTAL_RECV=0;
  333.   HTS_STAT.istat_bytes[0]=HTS_STAT.istat_bytes[1]=0;
  334.   if (opt->shell) {
  335.     last_info_shell=HTS_STAT.stat_timestart;
  336.   }
  337.   if ((opt->makestat) || (opt->maketrack)){
  338.     makestat_time=HTS_STAT.stat_timestart;
  339.   }
  340.   // init external modules
  341.   htspe_init();
  342.  
  343.   // initialiser cookie
  344.   if (opt->accept_cookie) {
  345.     opt->cookie=&cookie;
  346.     cookie.max_len=30000;       // max len
  347.     strcpybuff(cookie.data,"");
  348.     // Charger cookies.txt par dΘfaut ou cookies.txt du miroir
  349.     cookie_load(opt->cookie,StringBuff(opt->path_log),"cookies.txt");
  350.     cookie_load(opt->cookie,"","cookies.txt");
  351.   } else
  352.     opt->cookie=NULL;
  353.  
  354.   // initialiser exit_xh
  355.   opt->state.exit_xh=0;          // sortir prΘmaturΘment (var globale)
  356.  
  357.   // initialiser usercommand
  358.   usercommand(opt,opt->sys_com_exec,StringBuff(opt->sys_com),"","","");
  359.  
  360.   // initialiser structcheck
  361.   // structcheck_init(1);
  362.  
  363.   // initialiser verif_backblue
  364.   verif_backblue(opt,NULL);
  365.   verif_external(opt,0,0);
  366.   verif_external(opt,1,0);
  367.  
  368.   // et templates html
  369.   template_header=readfile_or(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_bin),"templates/index-header.html"),HTS_INDEX_HEADER);
  370.   template_body=readfile_or(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_bin),"templates/index-body.html"),HTS_INDEX_BODY);
  371.   template_footer=readfile_or(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_bin),"templates/index-footer.html"),HTS_INDEX_FOOTER);
  372.  
  373.   // initialiser mimedefs
  374.   //get_userhttptype(opt,1,StringBuff(opt->mimedefs),NULL);
  375.  
  376.   // Initialiser indexation
  377.   if (opt->kindex)
  378.     index_init(StringBuff(opt->path_html));
  379.  
  380.   // effacer bloc cache
  381.   memset(&cache, 0, sizeof(cache_back));
  382.   cache.type=opt->cache;  // cache?
  383.   cache.errlog=cache.log=opt->log;  // err log?
  384.   cache.ptr_ant=cache.ptr_last=0;   // pointeur pour anticiper
  385.  
  386.   // initialiser hash cache
  387.   if (!cache_hash_size) 
  388.     cache_hash_size=HTS_HASH_SIZE;
  389.   cache_hashtable=inthash_new(cache_hash_size);
  390.   cache_tests=inthash_new(cache_hash_size);
  391.   if (cache_hashtable==NULL || cache_tests==NULL) {
  392.     printf("PANIC! : Not enough memory [%d]\n",__LINE__);
  393.     filters[0]=NULL;    // uniquement a cause du warning de XH_extuninit
  394.     XH_extuninit;
  395.     return 0;
  396.   }
  397.   inthash_value_is_malloc(cache_tests, 1);     /* malloc */
  398.   cache.hashtable=(void*)cache_hashtable;      /* copy backcache hash */
  399.   cache.cached_tests=(void*)cache_tests;      /* copy of cache_tests */
  400.  
  401.   // robots.txt
  402.   strcpybuff(robots.adr,"!");    // dummy
  403.   robots.token[0]='\0';
  404.   robots.next=NULL;          // suivant
  405.   opt->robotsptr = &robots;
  406.   
  407.   // effacer filters
  408.   opt->maxfilter = maximum(opt->maxfilter, 128);
  409.   if (filters_init(&filters, opt->maxfilter, 0) == 0) {
  410.     printf("PANIC! : Not enough memory [%d]\n",__LINE__);
  411.     XH_extuninit;
  412.     return 0;
  413.   }
  414.   opt->filters.filters=&filters;
  415.   //
  416.   opt->filters.filptr=&filptr;
  417.   //opt->filters.filter_max=&filter_max;
  418.   
  419.   // hash table
  420.   opt->hash = &hash;
  421.  
  422.   // tableau de pointeurs sur les liens
  423.   lien_max=maximum(opt->maxlink,32);
  424.   liens=(lien_url**) malloct(lien_max*sizeof(lien_url*));   // tableau de pointeurs sur les liens
  425.   if (liens==NULL) {
  426.     printf("PANIC! : Not enough memory [%d]\n",__LINE__);
  427.     //XH_uninit;
  428.     return 0;
  429.   } else {
  430.     int i;
  431.     for(i=0;i<lien_max;i++) {
  432.       liens[i]=NULL;     
  433.     }
  434.   }
  435.   // initialiser ptr et lien_tot
  436.   ptr=0;
  437.   lien_tot=0;
  438.   // initialiser hachage
  439.   {
  440.     int i;
  441.     for(i=0;i<HTS_HASH_SIZE;i++)
  442.       hash.hash[0][i]=hash.hash[1][i]=hash.hash[2][i] = -1;    // pas d'entrΘes
  443.     hash.liens = liens;
  444.     hash.max_lien=0;
  445.   }
  446.  
  447.   // copier adresse(s) dans liste des adresses
  448.   {
  449.     char *a=url1;
  450.     int primary_len=8192;
  451.     if (StringNotEmpty(opt->filelist)) {
  452.       primary_len += max(0, fsize(StringBuff(opt->filelist))*2);
  453.     }
  454.     primary_len += (int) strlen(url1)*2;
  455.  
  456.     // crΘation de la premiΦre page, qui contient les liens de base α scanner
  457.     // c'est plus propre et plus logique que d'entrer α la main les liens dans la pile
  458.     // on bΘnΘficie ainsi des vΘrifications et des tests du robot pour les liens "primaires"
  459.     primary=(char*) malloct(primary_len); 
  460.     if (primary) {
  461.       primary[0]='\0';
  462.     } else {
  463.       printf("PANIC! : Not enough memory [%d]\n",__LINE__);
  464.       XH_extuninit;
  465.       return 0;
  466.     }
  467.     
  468.     while(*a) {
  469.       int i;
  470.       int joker=0;
  471.  
  472.       // vΘrifier qu'il n'y a pas de * dans l'url
  473.       if (*a=='+')
  474.         joker=1;
  475.       else if (*a=='-')
  476.         joker=1;
  477.       
  478.       if (joker) {    // joker ou filters
  479.         //char* p;
  480.         char BIGSTK tempo[HTS_URLMAXSIZE*2];
  481.         int type; int plus=0;
  482.  
  483.         // noter joker (dans b)
  484.         if (*a=='+') {  // champ +
  485.           type=1; plus=1; a++;
  486.         } else if (*a=='-') {  // champ forbidden[]
  487.           type=0; a++;
  488.         } else {  // champ + avec joker sans doute
  489.           type=1;
  490.         }
  491.  
  492.         // recopier prochaine chaine (+ ou -)
  493.         i=0;
  494.         while((*a!=0) && (!isspace((unsigned char)*a))) { tempo[i++]=*a; a++; }  
  495.         tempo[i++]='\0';
  496.         while(isspace((unsigned char)*a)) { a++; }
  497.  
  498.         // sauter les + sans rien aprΦs..
  499.         if (strnotempty(tempo)) {
  500.           if ((plus==0) && (type==1)) {  // implicite: *www.edf.fr par exemple
  501.             if (tempo[strlen(tempo)-1]!='*') {
  502.               strcatbuff(tempo,"*");  // ajouter un *
  503.             }
  504.           }
  505.           if (type)
  506.             strcpybuff(filters[filptr],"+");
  507.           else
  508.             strcpybuff(filters[filptr],"-");
  509.           strcatbuff(filters[filptr],tempo);
  510.           filptr++;
  511.           
  512.           /* sanity check */
  513.           if (filptr + 1 >= opt->maxfilter) {
  514.             opt->maxfilter += HTS_FILTERSINC;
  515.             if (filters_init(&filters, opt->maxfilter, HTS_FILTERSINC) == 0) {
  516.               printf("PANIC! : Too many filters : >%d [%d]\n",filptr,__LINE__);
  517.               if (opt->log) {
  518.                 fprintf(opt->log,LF"Too many filters, giving up..(>%d)"LF,filptr);
  519.                 fprintf(opt->log,"To avoid that: use #F option for more filters (example: -#F5000)"LF);
  520.                 test_flush;
  521.               }
  522.               XH_extuninit;
  523.               return 0;
  524.             }
  525.             //opt->filters.filters=filters;
  526.           }
  527.  
  528.         }
  529.         
  530.       } else {    // adresse normale
  531.         char BIGSTK url[HTS_URLMAXSIZE*2];
  532.         // prochaine adresse
  533.         i=0;
  534.         while((*a!=0) && (!isspace((unsigned char)*a))) { url[i++]=*a; a++; }  
  535.         while(isspace((unsigned char)*a)) { a++; }
  536.         url[i++]='\0';
  537.  
  538.         //strcatbuff(primary,"<PRIMARY=\"");
  539.         if (strstr(url,":/")==NULL)
  540.           strcatbuff(primary,"http://");
  541.         strcatbuff(primary,url);
  542.         //strcatbuff(primary,"\">");
  543.         strcatbuff(primary,"\n");
  544.       }
  545.     }  // while
  546.  
  547.     /* load URL file list */
  548.     /* OPTIMIZED for fast load */
  549.     if (StringNotEmpty(opt->filelist)) {
  550.       char* filelist_buff=NULL;
  551.       off_t filelist_sz = fsize(StringBuff(opt->filelist));
  552.       if (filelist_sz>0) {
  553.         FILE* fp=fopen(StringBuff(opt->filelist),"rb");
  554.         if (fp) {
  555.           filelist_buff = malloct(filelist_sz + 2);
  556.           if (filelist_buff) {
  557.             if (fread(filelist_buff,1,filelist_sz,fp) != filelist_sz) {
  558.               freet(filelist_buff);
  559.               filelist_buff=NULL;
  560.             } else {
  561.               *(filelist_buff + filelist_sz) = '\0';
  562.             }
  563.           }
  564.           fclose(fp);
  565.         }
  566.       }
  567.       
  568.       if (filelist_buff) {
  569.         int filelist_ptr=0;
  570.         int n=0;
  571.         char BIGSTK line[HTS_URLMAXSIZE*2];
  572.         char* primary_ptr = primary + strlen(primary);
  573.         while( filelist_ptr < filelist_sz ) {
  574.           int count=binput(filelist_buff+filelist_ptr,line,HTS_URLMAXSIZE);
  575.           filelist_ptr+=count;
  576.           if (count && line[0]) {
  577.             n++;
  578.             if (strstr(line,":/")==NULL) {
  579.               strcpybuff(primary_ptr, "http://");
  580.               primary_ptr += strlen(primary_ptr);
  581.             }
  582.             strcpybuff(primary_ptr, line);
  583.             primary_ptr += strlen(primary_ptr);
  584.             strcpybuff(primary_ptr, "\n");
  585.             primary_ptr += 1;
  586.           }
  587.         }
  588.         // fclose(fp);
  589.         if (opt->log!=NULL) {
  590.           HTS_LOG(opt,LOG_INFO); fprintf(opt->log,"%d links added from %s"LF,n,StringBuff(opt->filelist)); test_flush;
  591.         }
  592.  
  593.         // Free buffer
  594.         freet(filelist_buff);
  595.       } else {
  596.         if (opt->log!=NULL) {
  597.           HTS_LOG(opt,LOG_ERROR); fprintf(opt->log,"Could not include URL list: %s"LF,StringBuff(opt->filelist)); test_flush;
  598.         }
  599.       }
  600.     }
  601.  
  602.  
  603.     // lien primaire
  604.     liens_record("primary","/primary",fslash(OPT_GET_BUFF(opt),fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_html),"index.html")),"","",opt->urlhack);
  605.     if (liens[lien_tot]==NULL) {  // erreur, pas de place rΘservΘe
  606.       printf("PANIC! : Not enough memory [%d]\n",__LINE__);
  607.       if (opt->log) {
  608.         fprintf(opt->log,"Not enough memory, can not re-allocate %d bytes"LF,(int)((add_tab_alloc+1)*sizeof(lien_url)));
  609.         test_flush;
  610.       }
  611.       XH_extuninit;    // dΘsallocation mΘmoire & buffers
  612.       return 0;
  613.     }    
  614.     liens[lien_tot]->testmode=0;          // pas mode test
  615.     liens[lien_tot]->link_import=0;       // pas mode import
  616.     liens[lien_tot]->depth=opt->depth+1;   // lien de prioritΘ maximale
  617.     liens[lien_tot]->pass2=0;             // 1Φre passe
  618.     liens[lien_tot]->retry=opt->retry;     // lien de prioritΘ maximale
  619.     liens[lien_tot]->premier=lien_tot;    // premier lien, objet-pΦre=objet              
  620.     liens[lien_tot]->precedent=lien_tot;  // lien prΘcΘdent
  621.     lien_tot++;  
  622.  
  623.     // Initialiser cache
  624.     {
  625.       int backupXFR = htsMemoryFastXfr;
  626.       opt->state._hts_in_html_parsing=4;
  627.       if (!RUN_CALLBACK7(opt, loop, NULL,0,0,0,lien_tot,0,NULL)) {
  628.         opt->state.exit_xh=1;  // exit requested
  629.       }
  630.       htsMemoryFastXfr = 1;               /* fast load */
  631.       cache_init(&cache,opt);
  632.       htsMemoryFastXfr = backupXFR;
  633.       opt->state._hts_in_html_parsing=0;
  634.     }
  635.  
  636.   }
  637.   
  638. #if BDEBUG==3
  639.   {
  640.     int i;
  641.     for(i=0;i<lien_tot;i++) {
  642.       printf("%d>%s%s as %s\n",i,liens[i]->adr,liens[i]->fil,liens[i]->sav);
  643.     }
  644.     for(i=0;i<filptr;i++) {
  645.       printf("%d>filters=%s\n",i,filters[i]);
  646.     }
  647.   }
  648. #endif
  649.    
  650.   // backing
  651.   //soc_max=opt->maxsoc;
  652.   if (opt->maxsoc>0) {
  653. #if BDEBUG==2
  654.     _CLRSCR;
  655. #endif
  656.     // Nombre de fichiers HTML pouvant Ωtre prΘsents en mΘmoire de maniΦre simultannΘe
  657.     // On prΘvoit large: les fichiers HTML ne prennent que peu de place en mΘmoire, et les
  658.     // fichiers non html sont sauvΘs en direct sur disque.
  659.     // --> 1024 entrΘes + 32 entrΘes par socket en supplΘment
  660.     sback = back_new(opt->maxsoc*32+1024);   
  661.     if (sback == NULL) {
  662.       if (opt->log)
  663.         fprintf(opt->log,"Not enough memory, can not allocate %d bytes"LF,(int)((opt->maxsoc+1)*sizeof(lien_back)));
  664.       return 0;
  665.     }
  666.   }
  667.  
  668.  
  669.   // flush
  670.   test_flush;
  671.  
  672.   // statistiques
  673.   if (opt->makestat) {
  674.     makestat_fp=fopen(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-stats.txt"),"wb");
  675.     if (makestat_fp != NULL) {
  676.       fprintf(makestat_fp,"HTTrack statistics report, every minutes"LF LF);
  677.       fflush(makestat_fp);
  678.     }
  679.   }
  680.  
  681.   // tracking -- dΘbuggage
  682.   if (opt->maketrack) {
  683.     maketrack_fp=fopen(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-track.txt"),"wb");
  684.     if (maketrack_fp != NULL) {
  685.       fprintf(maketrack_fp,"HTTrack tracking report, every minutes"LF LF);
  686.       fflush(maketrack_fp);
  687.     }
  688.   }
  689.  
  690.   // on n'a pas de liens!! (exemple: httrack www.* impossible sans dΘpart..)
  691.   if (lien_tot<=0) {
  692.     if (opt->log) {
  693.       fprintf(opt->log,"Error! You MUST specify at least one complete URL, and not only wildcards!"LF);
  694.     }
  695.   }
  696.  
  697.   /* Send options to callback functions */
  698.   RUN_CALLBACK0(opt, chopt);
  699.  
  700.   // attendre une certaine heure..
  701.   if (opt->waittime>0) {
  702.     int rollover=0;
  703.     int ok=0;
  704.     {
  705.       TStamp tl=0;
  706.       time_t tt;
  707.       struct tm* A;
  708.       tt=time(NULL);
  709.       A=localtime(&tt);
  710.       tl+=A->tm_sec;
  711.       tl+=A->tm_min*60;
  712.       tl+=A->tm_hour*60*60;
  713.       if (tl>opt->waittime)  // attendre minuit
  714.         rollover=1;
  715.     }
  716.  
  717.     // attendre..
  718.     opt->state._hts_in_html_parsing=5;
  719.     do {
  720.       TStamp tl=0;
  721.       time_t tt;
  722.       struct tm* A;
  723.       tt=time(NULL);
  724.       A=localtime(&tt);
  725.       tl+=A->tm_sec;
  726.       tl+=A->tm_min*60;
  727.       tl+=A->tm_hour*60*60;
  728.  
  729.       if (rollover) {
  730.         if (tl<=opt->waittime)
  731.           rollover=0;  // attendre heure
  732.       } else {
  733.         if (tl>opt->waittime)
  734.           ok=1;  // ok!
  735.       }
  736.       
  737.       {  
  738.         int r;
  739.         if (rollover)
  740.           r = RUN_CALLBACK7(opt, loop, sback->lnk, sback->count,0,0,lien_tot,(int) (opt->waittime-tl+24*3600),NULL);
  741.         else
  742.           r = RUN_CALLBACK7(opt, loop, sback->lnk, sback->count,0,0,lien_tot,(int) (opt->waittime-tl),NULL);
  743.         if (!r) {
  744.           opt->state.exit_xh=1;  // exit requested
  745.           ok=1;          
  746.         } else
  747.           Sleep(100);
  748.       }
  749.  
  750.         } while(!ok);    
  751.     opt->state._hts_in_html_parsing=0;
  752.     
  753.     // note: recopie de plus haut
  754.     // noter heure actuelle de dΘpart en secondes
  755.     HTS_STAT.stat_timestart=time_local();
  756.     if (opt->shell) {
  757.       last_info_shell=HTS_STAT.stat_timestart;
  758.     }
  759.     if ((opt->makestat) || (opt->maketrack)){
  760.       makestat_time=HTS_STAT.stat_timestart;
  761.     }
  762.  
  763.  
  764.   }  
  765.   /* Info for wrappers */
  766.   if ( (opt->debug>0) && (opt->log!=NULL) ) {
  767.     HTS_LOG(opt,LOG_INFO); fprintf(opt->log,"engine: start"LF);
  768.   }
  769.   if (!RUN_CALLBACK0(opt, start)) {
  770.     XH_extuninit;
  771.     return 1;
  772.   }
  773.  
  774.   // ------------------------------------------------------------
  775.  
  776.   // ------------------------------------------------------------
  777.   // Boucle gΘnΘrale de parcours des liens
  778.   // ------------------------------------------------------------
  779.   do {
  780.     int error=0;          // si error alors sauter
  781.     int store_errpage=0;  // c'est une erreur mais on enregistre le html
  782.     char BIGSTK loc[HTS_URLMAXSIZE*2];    // adresse de relocation
  783.  
  784.     // Ici on charge le fichier (html, gif..) en mΘmoire
  785.     // Les HTMLs sont traitΘs (si leur prioritΘ est suffisante)
  786.  
  787.     // effacer r
  788.     memset(&r, 0, sizeof(htsblk)); r.soc=INVALID_SOCKET;
  789.     r.location=loc;    // en cas d'erreur 3xx (moved)
  790.     // recopier proxy
  791.     if ((r.req.proxy.active = opt->proxy.active)) {
  792.       if (StringBuff(opt->proxy.bindhost) != NULL)
  793.         strcpybuff(r.req.proxy.bindhost, StringBuff(opt->proxy.bindhost));
  794.       if (StringBuff(opt->proxy.name) != NULL)
  795.         strcpybuff(r.req.proxy.name, StringBuff(opt->proxy.name));
  796.       r.req.proxy.port = opt->proxy.port;
  797.     }
  798.     // et user-agent
  799.     strcpy(r.req.user_agent,StringBuff(opt->user_agent));
  800.     strcpy(r.req.referer,StringBuff(opt->referer));
  801.     strcpy(r.req.from,StringBuff(opt->from));
  802.     strcpy(r.req.lang_iso,StringBuff(opt->lang_iso));
  803.     r.req.user_agent_send=opt->user_agent_send;
  804.  
  805.     if (!error) {
  806.       
  807.       // Skip empty/invalid/done in background
  808.       if (liens[ptr]) {
  809.         while (  (liens[ptr]) && (
  810.                     ( ((urladr != NULL)?(urladr):(" "))[0]=='!') ||
  811.                     ( ((urlfil != NULL)?(urlfil):(" "))[0]=='\0') ||
  812.                     ( (liens[ptr]->pass2 == -1) )
  813.                  )
  814.                ) {  // sauter si lien annulΘ (ou fil vide)
  815.           if ((opt->debug>1) && (opt->log!=NULL)) {
  816.                         if (liens[ptr] != NULL && liens[ptr]->pass2 == -1) {
  817.                 HTS_LOG(opt,LOG_DEBUG); fprintf(opt->log,"link #%d is ready, skipping: %s%s.."LF,ptr,((urladr != NULL)?(urladr):(" ")),((urlfil != NULL)?(urlfil):(" ")));
  818.                         } else {
  819.                 HTS_LOG(opt,LOG_DEBUG); fprintf(opt->log,"link #%d seems ready, skipping: %s%s.."LF,ptr,((urladr != NULL)?(urladr):(" ")),((urlfil != NULL)?(urlfil):(" ")));
  820.                         }
  821.             test_flush;
  822.           }
  823.           // remove from stats
  824.           if (liens[ptr]->pass2 == -1) {
  825.             HTS_STAT.stat_background--;
  826.           }
  827.           ptr++;
  828.         }
  829.       }
  830.       if (liens[ptr]) {    // on a qq chose α rΘcupΘrer?
  831.  
  832.         if ( (opt->debug>1) && (opt->log!=NULL) ) {
  833.           HTS_LOG(opt,LOG_DEBUG); fprintf(opt->log,"Wait get: %s%s"LF,urladr,urlfil);
  834.           test_flush;
  835. #if DEBUG_ROBOTS
  836.           if (strcmp(urlfil,"/robots.txt") == 0) {
  837.             printf("robots.txt detected\n");
  838.           }
  839. #endif
  840.         }    
  841.         // ------------------------------------------------------------
  842.         // DEBUT --RECUPERATION LIEN---
  843.         if (ptr==0) {              // premier lien α parcourir: lien primaire construit avant
  844.           r.adr=primary; primary=NULL;
  845.           r.statuscode=HTTP_OK;
  846.           r.size=strlen(r.adr);
  847.           r.soc=INVALID_SOCKET;
  848.           strcpybuff(r.contenttype,"text/html");
  849.         /*} else if (opt->maxsoc<=0) {   // fichiers 1 α 1 en attente (pas de backing)
  850.           // charger le fichier en mΘmoire tout bΩtement
  851.           r=xhttpget(urladr,urlfil);
  852.           //
  853.         */
  854.         } else {    // backing, multiples sockets
  855.           
  856.           
  857.           /*
  858.             **************************************
  859.             Get the next link, waiting for other files, handling external callbacks
  860.           */
  861.           {
  862.             char BIGSTK buff_err_msg[1024];
  863.             htsmoduleStruct BIGSTK str;
  864.             htsmoduleStructExtended BIGSTK stre;
  865.             buff_err_msg[0] = '\0';
  866.             memset(&str, 0, sizeof(str));
  867.             memset(&stre, 0, sizeof(stre));
  868.             /* */
  869.             str.err_msg = buff_err_msg;
  870.             str.filename = savename;
  871.             str.mime = r.contenttype;
  872.             str.url_host = urladr;
  873.             str.url_file = urlfil;
  874.             str.size = (const int) r.size;
  875.             /* */
  876.             str.addLink = htsAddLink;
  877.             /* */
  878.             str.liens = liens;
  879.             str.opt = opt;
  880.             str.sback = sback;
  881.             str.cache = &cache;
  882.             str.hashptr = hashptr;
  883.             str.numero_passe = numero_passe;
  884.             str.add_tab_alloc = add_tab_alloc;
  885.             /* */
  886.             str.lien_tot_ = &lien_tot;
  887.             str.ptr_ = &ptr;
  888.             str.lien_size_ = &lien_size;
  889.             str.lien_buffer_ = &lien_buffer;
  890.             /* */
  891.             /* */
  892.             stre.r_ = &r;
  893.             /* */
  894.             stre.error_ = &error;
  895.             stre.exit_xh_ = &opt->state.exit_xh;
  896.             stre.store_errpage_ = &store_errpage;
  897.             /* */
  898.             stre.base = base;
  899.             stre.codebase = codebase;
  900.             /* */
  901.             stre.filters_ = &filters;
  902.             stre.filptr_ = &filptr;
  903.             stre.robots_ = &robots;
  904.             stre.hash_ = &hash;
  905.             stre.lien_max_ = &lien_max;
  906.             /* */
  907.             stre.makeindex_done_ = &makeindex_done;
  908.             stre.makeindex_fp_ = &makeindex_fp;
  909.             stre.makeindex_links_ = &makeindex_links;
  910.             stre.makeindex_firstlink_ = makeindex_firstlink;
  911.             /* */
  912.             stre.template_header_ = template_header;
  913.             stre.template_body_ = template_body;
  914.             stre.template_footer_ = template_footer;
  915.             /* */
  916.             stre.stat_fragment_ = &stat_fragment;
  917.             stre.makestat_time = makestat_time;
  918.             stre.makestat_fp = makestat_fp;
  919.             stre.makestat_total_ = &makestat_total;
  920.             stre.makestat_lnk_ = &makestat_lnk;
  921.             stre.maketrack_fp = maketrack_fp;
  922.             /* FUNCTION DEPENDANT */
  923.             stre.loc_ = loc;
  924.             stre.last_info_shell_ = &last_info_shell;
  925.             stre.info_shell_ = &info_shell;
  926.  
  927.             /* Parse */
  928.             switch(hts_mirror_wait_for_next_file(&str, &stre)) {
  929.             case -1:
  930.               XH_uninit;
  931.               return -1;
  932.               break;
  933.             case 2:
  934.               // Jump to 'continue'
  935.               // This is one of the very very rare cases where goto
  936.               // is acceptable
  937.               // A supplemental flag and if( ) { } would be really messy
  938.               goto jump_if_done;
  939.             }
  940.             
  941.           }
  942.           
  943.           
  944.         }
  945.         // FIN --RECUPERATION LIEN--- 
  946.         // ------------------------------------------------------------
  947.         
  948.         
  949.         
  950.       } else {    // lien vide..
  951.         if (opt->log && opt->debug > 0) {
  952.           HTS_LOG(opt,LOG_WARNING); fprintf(opt->log,"Warning, link #%d empty"LF,ptr); test_flush;
  953.         }         
  954.         error=1;
  955.         goto jump_if_done;
  956.       }  // test si url existe (non vide!)
  957.       
  958.  
  959.  
  960.       // ---tester taille a posteriori---
  961.       // tester r.adr
  962.       if (!error) {
  963.         // erreur, pas de fichier chargΘ:
  964.         if ((!r.adr) && (r.is_write==0) 
  965.           && (r.statuscode!=301) 
  966.           && (r.statuscode!=302) 
  967.           && (r.statuscode!=303) 
  968.           && (r.statuscode!=307) 
  969.           && (r.statuscode!=412)
  970.           && (r.statuscode!=416)
  971.          ) { 
  972.           // error=1;
  973.           
  974.           // peut Ωtre que le fichier Θtait trop gros?
  975.           if ((istoobig(opt,r.totalsize,opt->maxfile_html,opt->maxfile_nonhtml,r.contenttype))
  976.            || (istoobig(opt,r.totalsize,opt->maxfile_html,opt->maxfile_nonhtml,r.contenttype))) {
  977.             error=0;
  978.             if (opt->log) {
  979.               HTS_LOG(opt,LOG_WARNING); fprintf(opt->log,"Big file cancelled according to user's preferences: %s%s"LF,urladr,urlfil);
  980.               test_flush;
  981.             }
  982.           }
  983.           // // // error=1;    // ne pas traiter la suite -- euhh si finalement..
  984.         }
  985.       }
  986.       // ---fin tester taille a posteriori---    
  987.  
  988.       
  989.       // -------------------- 
  990.       // BOGUS MIME TYPE HACK
  991.       // Check if we have a bogus MIME type
  992.       // example: 
  993.       // Content-type="text/html"
  994.       // and 
  995.       // Content-disposition="foo.jpg"
  996.       // --------------------
  997.       if (!error) {
  998.         if (r.statuscode == HTTP_OK) {    // OK (ou 304 en backing)
  999.           if (r.adr) {    // Written file
  1000.             if ( (is_hypertext_mime(opt,r.contenttype, urlfil))   /* Is HTML or Js, .. */
  1001.                             /* NO - real media is real media, and mms is mms, not HTML */
  1002.               /*|| (may_be_hypertext_mime(r.contenttype, urlfil) && (r.adr) )*/  /* Is real media, .. */
  1003.               ) {
  1004.               if (strnotempty(r.cdispo)) {      // Content-disposition set!
  1005.                 if (ishtml(opt, savename) == 0) {    // Non HTML!!
  1006.                   // patch it!
  1007.                   strcpybuff(r.contenttype,"application/octet-stream");
  1008.                 }
  1009.               }
  1010.             }
  1011.           }
  1012.         }
  1013.         
  1014.         // ------------------------------------
  1015.         // BOGUS MIME TYPE HACK II (the revenge)
  1016.         // Check if we have a bogus MIME type
  1017.         if ( (is_hypertext_mime(opt,r.contenttype, urlfil))   /* Is HTML or Js, .. */
  1018.           || (may_be_hypertext_mime(opt,r.contenttype, urlfil))  /* Is real media, .. */
  1019.           ) {
  1020.           if ((r.adr) && (r.size)) {
  1021.             unsigned int map[256];
  1022.             int i;
  1023.             unsigned int nspec = 0;
  1024.             map_characters((unsigned char*)r.adr, (unsigned int)r.size, (unsigned int*)map);
  1025.             for(i = 1 ; i < 32 ; i++) {   //  null chars ignored..
  1026.               if (!is_realspace(i) 
  1027.                 && i != 27        /* Damn you ISO2022-xx! */
  1028.                 ) {
  1029.                 nspec += map[i];
  1030.               }
  1031.             }
  1032.             /* On-the-fly UCS2 to UTF-8 conversion (note: UCS2 should never be used on the net) */
  1033.             if (
  1034.               map[0] > r.size/10
  1035.               &&
  1036.               r.size % 2 == 0
  1037.               &&
  1038.               (
  1039.               ( ((unsigned char) r.adr[0]) == 0xff && ((unsigned char) r.adr[1]) == 0xfe)
  1040.                             ||
  1041.                             ( ((unsigned char) r.adr[0]) == 0xfe && ((unsigned char) r.adr[1]) == 0xff)
  1042.                             )
  1043.                             ) 
  1044.                         {
  1045. #define CH_ADD(c) do {                                                            \
  1046.     if (new_offs + 1 > new_capa) {                                        \
  1047.         new_capa *= 2;                                                                    \
  1048.         new_adr = (unsigned char*) realloct(new_adr,    \
  1049.                                             new_capa);     \
  1050.         assertf(new_adr != NULL);                                                \
  1051.     }                                                                                                    \
  1052.     new_adr[new_offs++] = (unsigned char) (c);        \
  1053. } while(0)
  1054. #define CH_ADD_RNG1(c, r, o) do {                   \
  1055.     CH_ADD( (c) / (r) + (o) );                        \
  1056.     c = (c) % (r);                                    \
  1057. } while(0)
  1058. #define CH_ADD_RNG0(c, o) do {                      \
  1059.     CH_ADD_RNG1(c, 1, o);                                                          \
  1060. } while(0)
  1061. #define CH_ADD_RNG2(c, r, r2, o) do {               \
  1062.     CH_ADD_RNG1(c, (r) * (r2), o);                                         \
  1063. } while(0)
  1064.                             int new_capa = (int) ( r.size / 2 + 1 );
  1065.                             int new_offs = 0;
  1066.                             unsigned char* prev_adr = (unsigned char*) r.adr;
  1067.                             unsigned char* new_adr = (unsigned char*) malloct(new_capa);
  1068.                             int i;
  1069.                             int swap = (((unsigned char)r.adr[0]) == 0xff);
  1070.                             assertf(new_adr != NULL);
  1071.                             /* 
  1072.                             See http://www.unicode.org/reports/tr28/tr28-3.html#conformance 
  1073.                             U+0000..U+007F 00..7F       
  1074.                             U+0080..U+07FF C2..DF  80..BF      
  1075.                             U+0800..U+0FFF E0      A0..BF  80..BF    
  1076.                             U+1000..U+CFFF E1..EC  80..BF  80..BF    
  1077.                             U+D000..U+D7FF ED      80..9F  80..BF    
  1078.                             U+D800..U+DFFF
  1079.                             U+E000..U+FFFF EE..EF  80..BF  80..BF    
  1080.                             */
  1081.                             for(i = 0 ; i < r.size / 2 ; i++) {
  1082.                                 unsigned short int unic = 0;
  1083.                                 if (swap)
  1084.                                     unic = prev_adr[i*2] + (prev_adr[i*2 + 1] << 8);
  1085.                                 else
  1086.                                     unic = (prev_adr[i*2] << 8) + prev_adr[i*2 + 1];
  1087.                                 if (unic <= 0x7F) {
  1088.                                     /* U+0000..U+007F 00..7F      */
  1089.                                     CH_ADD_RNG0( unic,               0x00 );
  1090.                                 } else if (unic <= 0x07FF) {
  1091.                                     /* U+0080..U+07FF C2..DF  80..BF */
  1092.                                     unic -= 0x0080;
  1093.                                     CH_ADD_RNG1( unic, 0xbf - 0x80 + 1, 0xc2 );
  1094.                                     CH_ADD_RNG0( unic,                  0x80 );
  1095.                                 } else if (unic <= 0x0FFF) {
  1096.                                     /* U+0800..U+0FFF E0      A0..BF  80..BF */
  1097.                                     unic -= 0x0800;
  1098.                                     CH_ADD_RNG2( unic, 0xbf - 0x80 + 1, 0xbf - 0xa0 + 1, 0xe0 );
  1099.                                     CH_ADD_RNG1( unic, 0xbf - 0x80 + 1, 0xa0 );
  1100.                                     CH_ADD_RNG0( unic,                  0x80 );
  1101.                                 } else if (unic <= 0xCFFF) {
  1102.                                     /* U+1000..U+CFFF E1..EC  80..BF  80..BF */
  1103.                                     unic -= 0x1000;
  1104.                                     CH_ADD_RNG2( unic, 0xbf - 0x80 + 1, 0xbf - 0x80 + 1, 0xe1 );
  1105.                                     CH_ADD_RNG1( unic, 0xbf - 0x80 + 1, 0x80 );
  1106.                                     CH_ADD_RNG0( unic,                  0x80 );
  1107.                                 } else if (unic <= 0xD7FF) {
  1108.                                     /* U+D000..U+D7FF ED      80..9F  80..BF */
  1109.                                     unic -= 0xD000;
  1110.                                     CH_ADD_RNG2( unic, 0xbf - 0x80 + 1, 0x9f - 0x80 + 1, 0xed );
  1111.                                     CH_ADD_RNG1( unic, 0xbf - 0x80 + 1, 0x80 );
  1112.                                     CH_ADD_RNG0( unic,                  0x80 );
  1113.                                 } else if (unic <= 0xDFFF) {
  1114.                                     /* U+D800..U+DFFF */
  1115.                                     CH_ADD('?');
  1116.                                     /* ill-formed */
  1117.                                 } else /* if (unic <= 0xFFFF) */ {
  1118.                                     /* U+E000..U+FFFF EE..EF  80..BF  80..BF */
  1119.                                     unic -= 0xE000;
  1120.                                     CH_ADD_RNG2( unic, 0xbf - 0x80 + 1, 0xbf - 0x80 + 1, 0xee );
  1121.                                     CH_ADD_RNG1( unic, 0xbf - 0x80 + 1, 0x80 );
  1122.                                     CH_ADD_RNG0( unic,                  0x80 );
  1123.                                 }
  1124.                             }
  1125.                             if (opt->log) {
  1126.                                 HTS_LOG(opt,LOG_WARNING); fprintf(opt->log,"File %s%s converted from UCS2 to UTF-8 (old size: %d bytes, new size: %d bytes)"LF, urladr, urlfil, (int)r.size, new_offs);
  1127.                                 test_flush;
  1128.                             }
  1129.                             freet(r.adr);
  1130.                             r.adr = NULL;
  1131.                             r.size = new_offs;
  1132.                             CH_ADD(0);
  1133.                             r.adr = (char*) new_adr;
  1134. #undef CH_ADD
  1135. #undef CH_ADD_RNG0
  1136. #undef CH_ADD_RNG1
  1137. #undef CH_ADD_RNG2
  1138.                         } else if ((nspec > r.size / 100) && (nspec > 10)) {    // too many special characters
  1139.                             strcpybuff(r.contenttype,"application/octet-stream");
  1140.                             if (opt->log) {
  1141.                                 HTS_LOG(opt,LOG_WARNING); fprintf(opt->log,"File not parsed, looks like binary: %s%s"LF,urladr,urlfil);
  1142.                                 test_flush;
  1143.                             }
  1144.                         }
  1145.  
  1146.                         /* This hack allows to avoid problems with parsing '\0' characters  */
  1147.                         for(i = 0 ; i < r.size ; i++) {
  1148.                             if (r.adr[i] == '\0') r.adr[i] = ' ';
  1149.                         }
  1150.  
  1151.           }
  1152.  
  1153.  
  1154.         }
  1155.       }
  1156.       
  1157.             // MOVED IN back_finalize()
  1158.             //
  1159.       // -------------------- 
  1160.       // REAL MEDIA HACK
  1161.       // Check if we have to load locally the file
  1162.       // --------------------
  1163.       //if (!error) {
  1164.       //  if (r.statuscode == HTTP_OK) {    // OK (ou 304 en backing)
  1165.       //    if (r.adr==NULL) {    // Written file
  1166.       //      if (may_be_hypertext_mime(r.contenttype, urlfil)) {   // to parse!
  1167.       //        LLint sz;
  1168.       //        sz=fsize(savename);
  1169.       //        if (sz>0) {   // ok, exists!
  1170.       //          if (sz < 8192) {   // ok, small file --> to parse!
  1171.       //            FILE* fp=fopen(savename,"rb");
  1172.       //            if (fp) {
  1173.       //              r.adr=malloct((int)sz + 2);
  1174.       //              if (r.adr) {
  1175.       //                if (fread(r.adr,1,sz,fp) == sz) {
  1176.       //                  r.size=sz;
  1177.       //                        r.adr[sz] = '\0';
  1178.       //                        r.is_write = 0;
  1179.       //                } else {
  1180.       //                  freet(r.adr);
  1181.       //                  r.size=0;
  1182.       //                  r.adr = NULL;
  1183.       //                  r.statuscode=STATUSCODE_INVALID;
  1184.       //                  strcpybuff(r.msg, ".RAM read error");
  1185.       //                }
  1186.       //                fclose(fp);
  1187.       //                fp=NULL;
  1188.       //                // remove (temporary) file!
  1189.       //                remove(savename);
  1190.       //              }
  1191.       //              if (fp)
  1192.       //                fclose(fp);
  1193.       //            }
  1194.       //          }
  1195.       //        }
  1196.       //      }
  1197.       //    }
  1198.       //  }
  1199.       //}
  1200.       // EN OF REAL MEDIA HACK
  1201.       
  1202.  
  1203.       // ---stockage en cache---
  1204.       // stocker dans le cache?
  1205.       /*
  1206.       if (!error) {
  1207.         if (ptr>0) {
  1208.           if (liens[ptr]) {
  1209.             xxcache_mayadd(opt,&cache,&r,urladr,urlfil,savename);
  1210.           } else
  1211.             error=1;
  1212.         }
  1213.       }
  1214.       */
  1215.       // ---fin stockage en cache---
  1216.       
  1217.       
  1218.       
  1219.       /*
  1220.          **************************************
  1221.          Check "Moved permanently" and other similar errors, retrying URLs if necessary and handling
  1222.          redirect pages.
  1223.       */
  1224.       if (!error) {
  1225.         char BIGSTK buff_err_msg[1024];
  1226.         htsmoduleStruct BIGSTK str;
  1227.         htsmoduleStructExtended BIGSTK stre;
  1228.         buff_err_msg[0] = '\0';
  1229.         memset(&str, 0, sizeof(str));
  1230.         memset(&stre, 0, sizeof(stre));
  1231.         /* */
  1232.         str.err_msg = buff_err_msg;
  1233.         str.filename = savename;
  1234.         str.mime = r.contenttype;
  1235.         str.url_host = urladr;
  1236.         str.url_file = urlfil;
  1237.         str.size = (int) r.size;
  1238.         /* */
  1239.         str.addLink = htsAddLink;
  1240.         /* */
  1241.         str.liens = liens;
  1242.         str.opt = opt;
  1243.         str.sback = sback;
  1244.         str.cache = &cache;
  1245.         str.hashptr = hashptr;
  1246.         str.numero_passe = numero_passe;
  1247.         str.add_tab_alloc = add_tab_alloc;
  1248.         /* */
  1249.         str.lien_tot_ = &lien_tot;
  1250.         str.ptr_ = &ptr;
  1251.         str.lien_size_ = &lien_size;
  1252.         str.lien_buffer_ = &lien_buffer;
  1253.         /* */
  1254.         /* */
  1255.         stre.r_ = &r;
  1256.         /* */
  1257.         stre.error_ = &error;
  1258.         stre.exit_xh_ = &opt->state.exit_xh;
  1259.         stre.store_errpage_ = &store_errpage;
  1260.         /* */
  1261.         stre.base = base;
  1262.         stre.codebase = codebase;
  1263.         /* */
  1264.         stre.filters_ = &filters;
  1265.         stre.filptr_ = &filptr;
  1266.         stre.robots_ = &robots;
  1267.         stre.hash_ = &hash;
  1268.         stre.lien_max_ = &lien_max;
  1269.         /* */
  1270.         stre.makeindex_done_ = &makeindex_done;
  1271.         stre.makeindex_fp_ = &makeindex_fp;
  1272.         stre.makeindex_links_ = &makeindex_links;
  1273.         stre.makeindex_firstlink_ = makeindex_firstlink;
  1274.         /* */
  1275.         stre.template_header_ = template_header;
  1276.         stre.template_body_ = template_body;
  1277.         stre.template_footer_ = template_footer;
  1278.         /* */
  1279.         stre.stat_fragment_ = &stat_fragment;
  1280.         stre.makestat_time = makestat_time;
  1281.         stre.makestat_fp = makestat_fp;
  1282.         stre.makestat_total_ = &makestat_total;
  1283.         stre.makestat_lnk_ = &makestat_lnk;
  1284.         stre.maketrack_fp = maketrack_fp;
  1285.         
  1286.         /* Parse */
  1287.         if (hts_mirror_check_moved(&str, &stre) != 0) {
  1288.           XH_uninit;
  1289.           return -1;
  1290.         }
  1291.         
  1292.       }
  1293.  
  1294.     }  // if !error
  1295.     
  1296.     if (!error) {
  1297. #if DEBUG_SHOWTYPES
  1298.       if (strstr(REG,r.contenttype)==NULL) {
  1299.         strcatbuff(REG,r.contenttype);
  1300.         strcatbuff(REG,"\n");
  1301.         printf("%s\n",r.contenttype);
  1302.         io_flush;
  1303.       }
  1304. #endif
  1305.       
  1306.       /* Load file if necessary */
  1307.       if ( 
  1308.         may_be_hypertext_mime(opt,r.contenttype, urlfil)   /* Is HTML or Js, .. */
  1309.         && (liens[ptr]->depth>0)            /* Depth > 0 (recurse depth) */
  1310.         && (r.adr==NULL)        /* HTML Data exists */
  1311.         && (!store_errpage)     /* Not an html error page */
  1312.         && (savename[0]!='\0')  /* Output filename exists */
  1313.         ) 
  1314.       {
  1315.         r.adr = readfile2(savename, &r.size);
  1316.         (void) unlink(fconv(OPT_GET_BUFF(opt),savename));
  1317.         if (r.adr != NULL) {
  1318.           if ( (opt->debug>0) && (opt->log!=NULL) ) {
  1319.             HTS_LOG(opt,LOG_INFO); fprintf(opt->log,"File successfully loaded for parsing: %s%s (%d bytes)"LF,urladr,urlfil,(int)r.size);
  1320.             test_flush;
  1321.           }
  1322.         } else {
  1323.           if ( opt->log != NULL ) {
  1324.             HTS_LOG(opt,LOG_ERROR); fprintf(opt->log,"File could not be loaded for parsing: %s%s"LF,urladr,urlfil);
  1325.             test_flush;
  1326.           }
  1327.         }
  1328.       }
  1329.  
  1330.       // ------------------------------------------------------
  1331.       // ok, fichier chargΘ localement
  1332.       // ------------------------------------------------------
  1333.       
  1334.       // VΘrificateur d'intΘgritΘ
  1335.       #if DEBUG_CHECKINT
  1336.       {
  1337.         int i;
  1338.         for(i = 0 ; i < sback->count ; i++) {
  1339.           char si[256];
  1340.           sprintf(si,"Test global aprΦs back_wait, index %d",i);
  1341.           _CHECKINT(&back[i],si)
  1342.         }
  1343.       }
  1344.       #endif
  1345.  
  1346.  
  1347.       /* info: updated */
  1348.       /*
  1349.       if (ptr>0) {
  1350.         // "mis α jour"
  1351.         if ((!r.notmodified) && (opt->is_update) && (!store_errpage)) {    // page modifiΘe
  1352.           if (strnotempty(savename)) {
  1353.             HTS_STAT.stat_updated_files++;
  1354.             if (opt->log!=NULL) {
  1355.               //if ((opt->debug>0) && (opt->log!=NULL)) {
  1356.               HTS_LOG(opt,LOG_INFO); fprintf(opt->log,"File updated: %s%s"LF,urladr,urlfil);
  1357.               test_flush;
  1358.             }
  1359.           }
  1360.         } else {
  1361.           if (!store_errpage) {
  1362.             if ( (opt->debug>0) && (opt->log!=NULL) ) {
  1363.               HTS_LOG(opt,LOG_INFO); fprintf(opt->log,"File recorded: %s%s"LF,urladr,urlfil);
  1364.               test_flush;
  1365.             }
  1366.           }
  1367.         }
  1368.       }
  1369.       */
  1370.       
  1371.       // ------------------------------------------------------
  1372.       // traitement (parsing)
  1373.       // ------------------------------------------------------
  1374.  
  1375.       // traiter
  1376.       if (
  1377.            ( (is_hypertext_mime(opt,r.contenttype, urlfil))   /* Is HTML or Js, .. */
  1378.              || (may_be_hypertext_mime(opt,r.contenttype, urlfil) && r.adr != NULL )  /* Is real media, .. */
  1379.            )
  1380.         && (liens[ptr]->depth>0)            /* Depth > 0 (recurse depth) */
  1381.         && (r.adr!=NULL)        /* HTML Data exists */
  1382.         && (r.size>0)           /* And not empty */
  1383.         && (!store_errpage)     /* Not an html error page */
  1384.         && (savename[0]!='\0')  /* Output filename exists */
  1385.         ) {    // ne traiter que le html si autorisΘ
  1386.         // -- -- -- --
  1387.         // Parsing HTML
  1388.         if (!error) {
  1389.           /* Info for wrappers */
  1390.           if ( (opt->debug>0) && (opt->log!=NULL) ) {
  1391.             HTS_LOG(opt,LOG_INFO); fprintf(opt->log,"engine: check-html: %s%s"LF,urladr,urlfil);
  1392.           }
  1393.           {
  1394.             char BIGSTK buff_err_msg[1024];
  1395.             htsmoduleStruct BIGSTK str;
  1396.             htsmoduleStructExtended BIGSTK stre;
  1397.             buff_err_msg[0] = '\0';
  1398.             memset(&str, 0, sizeof(str));
  1399.             memset(&stre, 0, sizeof(stre));
  1400.             /* */
  1401.             str.err_msg = buff_err_msg;
  1402.             str.filename = savename;
  1403.             str.mime = r.contenttype;
  1404.             str.url_host = urladr;
  1405.             str.url_file = urlfil;
  1406.             str.size = (int) r.size;
  1407.             /* */
  1408.             str.addLink = htsAddLink;
  1409.             /* */
  1410.             str.liens = liens;
  1411.             str.opt = opt;
  1412.             str.sback = sback;
  1413.             str.cache = &cache;
  1414.             str.hashptr = hashptr;
  1415.             str.numero_passe = numero_passe;
  1416.             str.add_tab_alloc = add_tab_alloc;
  1417.             /* */
  1418.             str.lien_tot_ = &lien_tot;
  1419.             str.ptr_ = &ptr;
  1420.             str.lien_size_ = &lien_size;
  1421.             str.lien_buffer_ = &lien_buffer;
  1422.             /* */
  1423.             /* */
  1424.             stre.r_ = &r;
  1425.             /* */
  1426.             stre.error_ = &error;
  1427.             stre.exit_xh_ = &opt->state.exit_xh;
  1428.             stre.store_errpage_ = &store_errpage;
  1429.             /* */
  1430.             stre.base = base;
  1431.             stre.codebase = codebase;
  1432.             /* */
  1433.             stre.filters_ = &filters;
  1434.             stre.filptr_ = &filptr;
  1435.             stre.robots_ = &robots;
  1436.             stre.hash_ = &hash;
  1437.             stre.lien_max_ = &lien_max;
  1438.             /* */
  1439.             stre.makeindex_done_ = &makeindex_done;
  1440.             stre.makeindex_fp_ = &makeindex_fp;
  1441.             stre.makeindex_links_ = &makeindex_links;
  1442.             stre.makeindex_firstlink_ = makeindex_firstlink;
  1443.             /* */
  1444.             stre.template_header_ = template_header;
  1445.             stre.template_body_ = template_body;
  1446.             stre.template_footer_ = template_footer;
  1447.             /* */
  1448.             stre.stat_fragment_ = &stat_fragment;
  1449.             stre.makestat_time = makestat_time;
  1450.             stre.makestat_fp = makestat_fp;
  1451.             stre.makestat_total_ = &makestat_total;
  1452.             stre.makestat_lnk_ = &makestat_lnk;
  1453.             stre.maketrack_fp = maketrack_fp;
  1454.             
  1455.             /* Parse */
  1456.             if (htsparse(&str, &stre) != 0) {
  1457.               XH_uninit;
  1458.               return -1;
  1459.             }
  1460.  
  1461.  
  1462.           // I'll have to segment this part
  1463. // #include "htsparse.c"
  1464.  
  1465.  
  1466.           }
  1467.         }
  1468.         // Fin parsing HTML
  1469.         // -- -- -- --
  1470.  
  1471.  
  1472.       }  // si text/html
  1473.       // -- -- --
  1474.       else {    // sauver fichier quelconque
  1475.         // -- -- --
  1476.         // sauver fichier
  1477.  
  1478.  
  1479.         /* En cas d'erreur, vΘrifier que fichier d'erreur existe */
  1480.         if (strnotempty(savename) == 0) {           // chemin de sauvegarde existant
  1481.           if (strcmp(urlfil,"/robots.txt")==0) {    // pas robots.txt
  1482.             if (store_errpage) {                    // c'est une page d'erreur
  1483.               int create_html_warning=0;
  1484.               int create_gif_warning=0;
  1485.               switch (ishtml(opt,urlfil)) {      /* pas fichier html */
  1486.               case 0:                        /* non html */
  1487.                 {
  1488.                   char buff[256];
  1489.                   guess_httptype(opt,buff,urlfil);
  1490.                   if (strcmp(buff,"image/gif")==0)
  1491.                     create_gif_warning=1;
  1492.                 }
  1493.                 break;
  1494.               case 1:                        /* html */
  1495.                 if (!r.adr) {
  1496.                 }
  1497.                 break;
  1498.               default:                       /* don't know.. */
  1499.                 break;    
  1500.               }
  1501.               /* CrΘer message d'erreur ? */
  1502.               if (create_html_warning) {
  1503.                 char* adr=(char*)malloct(strlen(HTS_DATA_ERROR_HTML)+1100);
  1504.                 if ( (opt->debug>0) && (opt->log!=NULL) ) {
  1505.                   HTS_LOG(opt,LOG_INFO); fprintf(opt->log,"Creating HTML warning file (%s)"LF,r.msg);
  1506.                   test_flush;
  1507.                 }
  1508.                 if (adr) {
  1509.                   if (r.adr) {
  1510.                     freet(r.adr);
  1511.                     r.adr=NULL;
  1512.                   }
  1513.                   sprintf(adr,HTS_DATA_ERROR_HTML,r.msg);
  1514.                   r.adr=adr;
  1515.                 }
  1516.               } else if (create_gif_warning) {
  1517.                 char* adr=(char*)malloct(HTS_DATA_UNKNOWN_GIF_LEN);
  1518.                 if ( (opt->debug>0) && (opt->log!=NULL) ) {
  1519.                   HTS_LOG(opt,LOG_INFO); fprintf(opt->log,"Creating GIF dummy file (%s)"LF,r.msg);
  1520.                   test_flush;
  1521.                 }
  1522.                 if (r.adr) {
  1523.                   freet(r.adr);
  1524.                   r.adr=NULL;
  1525.                 }
  1526.                 memcpy(adr, HTS_DATA_UNKNOWN_GIF, HTS_DATA_UNKNOWN_GIF_LEN);
  1527.                 r.adr=adr;
  1528.               }
  1529.             }
  1530.           }
  1531.         }
  1532.  
  1533.         if (strnotempty(savename) == 0) {    // pas de chemin de sauvegarde
  1534.           if (strcmp(urlfil,"/robots.txt")==0) {    // robots.txt
  1535.             if (r.adr) {
  1536.               int bptr=0;
  1537.               char BIGSTK line[1024];
  1538.               char BIGSTK buff[8192];
  1539.               char BIGSTK infobuff[8192];
  1540.               int record=0;
  1541.               line[0]='\0'; buff[0]='\0'; infobuff[0]='\0';
  1542.               //
  1543. #if DEBUG_ROBOTS
  1544.               printf("robots.txt dump:\n%s\n",r.adr);
  1545. #endif
  1546.               do {
  1547.                 char* comm;
  1548.                 int llen;
  1549.                 bptr+=binput(r.adr+bptr, line, sizeof(line) - 2);
  1550.                 /* strip comment */
  1551.                 comm=strchr(line, '#');
  1552.                 if (comm != NULL) {
  1553.                   *comm = '\0';
  1554.                 }
  1555.                 /* strip spaces */
  1556.                 llen = (int) strlen(line);
  1557.                 while(llen > 0 && is_realspace(line[llen - 1])) {
  1558.                   line[llen - 1] = '\0';
  1559.                   llen--;
  1560.                 }
  1561.                 if (strfield(line,"user-agent:")) {
  1562.                   char* a;
  1563.                   a=line+11;
  1564.                   while(is_realspace(*a)) a++;    // sauter espace(s)
  1565.                   if ( *a == '*') {
  1566.                     if (record != 2)
  1567.                       record=1;    // c pour nous
  1568.                   } else if (strfield(a,"httrack") || strfield(a,"winhttrack") || strfield(a,"webhttrack")) {
  1569.                     buff[0]='\0';      // re-enregistrer
  1570.                     infobuff[0]='\0';
  1571.                     record=2;          // locked
  1572. #if DEBUG_ROBOTS
  1573.                     printf("explicit disallow for httrack\n");
  1574. #endif
  1575.                   }
  1576.                   else record=0;
  1577.                 } else if (record) {
  1578.                   if (strfield(line,"disallow:")) {
  1579.                     char* a=line+9;
  1580.                     while(is_realspace(*a))
  1581.                       a++;    // sauter espace(s)
  1582.                     if (strnotempty(a)) {
  1583. #ifdef IGNORE_RESTRICTIVE_ROBOTS 
  1584.                       if (strcmp(a,"/") != 0 || opt->robots >= 3) 
  1585. #endif
  1586.                       {      /* ignoring disallow: / */
  1587.                         if ( (strlen(buff) + strlen(a) + 8) < sizeof(buff)) {
  1588.                           strcatbuff(buff,a);
  1589.                           strcatbuff(buff,"\n");
  1590.                           if ( (strlen(infobuff) + strlen(a) + 8) < sizeof(infobuff)) {
  1591.                             if (strnotempty(infobuff)) strcatbuff(infobuff,", ");
  1592.                             strcatbuff(infobuff,a);
  1593.                           }
  1594.                         }
  1595.                       }
  1596. #ifdef IGNORE_RESTRICTIVE_ROBOTS 
  1597.                       else {
  1598.                         if (opt->log!=NULL) {
  1599.                           HTS_LOG(opt,LOG_INFO); fprintf(opt->log,"Note: %s robots.txt rules are too restrictive, ignoring /"LF,urladr);
  1600.                           test_flush;
  1601.                         }
  1602.                       }
  1603. #endif
  1604.                     }
  1605.                   }
  1606.                 }
  1607.               } while( (bptr<r.size) && (strlen(buff) < (sizeof(buff) - 32) ) );
  1608.               if (strnotempty(buff)) {
  1609.                 checkrobots_set(&robots,urladr,buff);
  1610.                 if (opt->log!=NULL) {
  1611.                   if (opt->log != opt->log) {
  1612.                     HTS_LOG(opt,LOG_INFO); fprintf(opt->log,"Note: robots.txt forbidden links for %s are: %s"LF,urladr,infobuff);
  1613.                     test_flush;
  1614.                   } 
  1615.                 }
  1616.                 if (opt->log!=NULL) {
  1617.                   HTS_LOG(opt,LOG_INFO); fprintf(opt->log,"Note: due to %s remote robots.txt rules, links begining with these path will be forbidden: %s (see in the options to disable this)"LF,urladr,infobuff);
  1618.                   test_flush;
  1619.                 }
  1620.               }
  1621.             }
  1622.           }
  1623.         } else if (r.is_write) {    // dΘja sauvΘ sur disque
  1624.           /*
  1625.           if (!ishttperror(r.statuscode))
  1626.             HTS_STAT.stat_files++;
  1627.           HTS_STAT.stat_bytes+=r.size;
  1628.           */
  1629.           //printf("ok......\n");
  1630.         } else {
  1631.           // Si on doit sauver une page HTML sans la scanner, cela signifie que le niveau de
  1632.           // rΘcursion nous en empΩche
  1633.           // Dans ce cas on met un fichier indiquant ce fait
  1634.           // Si par la suite on doit retraiter ce fichier avec un niveau de rΘcursion plus
  1635.           // fort, on supprimera le readme, et on scannera le fichier html!
  1636.           // note: sautΘ si store_errpage (cαd si page d'erreur, non α scanner!)
  1637.           if ( (is_hypertext_mime(opt,r.contenttype, urlfil)) && (!store_errpage) && (r.size>0)) {  // c'est du html!!
  1638.             char BIGSTK tempo[HTS_URLMAXSIZE*2];
  1639.             FILE* fp;
  1640.             tempo[0]='\0';
  1641.             strcpybuff(tempo,savename);
  1642.             strcatbuff(tempo,".readme");
  1643.             
  1644. #if HTS_DOSNAME
  1645.             // remplacer / par des slash arriΦre
  1646.             {
  1647.               int i=0;
  1648.               while(tempo[i]) {
  1649.                 if (tempo[i]=='/')
  1650.                   tempo[i]='\\';
  1651.                 i++;
  1652.               } 
  1653.             } 
  1654.             // a partir d'ici le slash devient antislash
  1655. #endif
  1656.             
  1657.             if ((fp=fopen(tempo,"wb"))!=NULL) {
  1658.               fprintf(fp,"Info-file generated by HTTrack Website Copier "HTTRACK_VERSION"%s"CRLF""CRLF, hts_get_version_info(opt));
  1659.               fprintf(fp,"The file %s has not been scanned by HTS"CRLF,savename);
  1660.               fprintf(fp,"Some links contained in it may be unreachable locally."CRLF);
  1661.               fprintf(fp,"If you want to get these files, you have to set an upper recurse level, ");
  1662.               fprintf(fp,"and to rescan the URL."CRLF);
  1663.               fclose(fp);
  1664. #ifndef _WIN32
  1665.               chmod(tempo,HTS_ACCESS_FILE);      
  1666. #endif
  1667.               usercommand(opt,0,NULL,fconv(OPT_GET_BUFF(opt),tempo),"","");
  1668.             }
  1669.             
  1670.             
  1671.             if ( (opt->debug>0) && (opt->log!=NULL) ) {
  1672.               HTS_LOG(opt,LOG_WARNING); fprintf(opt->log,"Warning: store %s without scan: %s"LF,r.contenttype,savename);
  1673.               test_flush;
  1674.             }
  1675.           } else {
  1676.             if ((opt->getmode & 2)!=0) {    // ok autorisΘ
  1677.               if ( (opt->debug>1) && (opt->log!=NULL) ) {
  1678.                 HTS_LOG(opt,LOG_DEBUG); fprintf(opt->log,"Store %s: %s"LF,r.contenttype,savename);
  1679.                 test_flush;
  1680.               }
  1681.             } else {    // lien non autorisΘ! (ex: cgi-bin en html)
  1682.               if ((opt->debug>1) && (opt->log!=NULL)) {
  1683.                 HTS_LOG(opt,LOG_DEBUG); fprintf(opt->log,"non-html file ignored after upload at %s : %s"LF,urladr,urlfil);
  1684.                 test_flush;
  1685.               } 
  1686.               if (r.adr) {
  1687.                 freet(r.adr); r.adr=NULL;
  1688.               }
  1689.             }
  1690.           }
  1691.           
  1692.           //printf("extern=%s\n",r.contenttype);
  1693.  
  1694.           // ATTENTION C'EST ICI QU'ON SAUVE LE FICHIER!!          
  1695.           if (r.adr) {
  1696.             file_notify(opt, urladr,urlfil, savename, 1, 1, r.notmodified);
  1697.             if (filesave(opt,r.adr,(int)r.size,savename,urladr,urlfil)!=0) {
  1698.               int fcheck;
  1699.               if ((fcheck=check_fatal_io_errno())) {
  1700.                                 HTS_LOG(opt,LOG_ERROR); fprintf(opt->log,"Mirror aborted: disk full or filesystem problems"LF); test_flush;
  1701.                 opt->state.exit_xh=-1;   /* fatal error */
  1702.               }
  1703.               if (opt->log) {   
  1704.                 int last_errno = errno;
  1705.                 HTS_LOG(opt,LOG_ERROR); fprintf(opt->log,"Unable to save file %s : %s"LF, savename, strerror(last_errno));
  1706.                 if (fcheck) {
  1707.                   HTS_LOG(opt,LOG_ERROR);
  1708.                   fprintf(opt->log,"* * Fatal write error, giving up"LF);
  1709.                 }
  1710.                 test_flush;
  1711.               }
  1712.             } else {
  1713.               /*
  1714.               if (!ishttperror(r.statuscode))
  1715.                 HTS_STAT.stat_files++;
  1716.               HTS_STAT.stat_bytes+=r.size;
  1717.               */
  1718.             }
  1719.           }
  1720.           
  1721.         }
  1722.   
  1723.  
  1724.         /* Parsing of other media types (java, ram..) */
  1725.         /*
  1726.         if (strfield2(r.contenttype,"audio/x-pn-realaudio")) {
  1727.           if ((opt->debug>1) && (opt->log!=NULL)) {
  1728.             HTS_LOG(opt,LOG_DEBUG); fprintf(opt->log,"(Real Media): parsing %s"LF,savename); test_flush;
  1729.           }
  1730.           if (fexist(savename)) {   // ok, existe bien!
  1731.             FILE* fp=fopen(savename,"r+b");
  1732.             if (fp) {
  1733.               if (!fseek(fp,0,SEEK_SET)) {
  1734.                 char BIGSTK line[HTS_URLMAXSIZE*2];
  1735.                 linput(fp,line,HTS_URLMAXSIZE);
  1736.                 if (strnotempty(line)) {
  1737.                   if ((opt->debug>1) && (opt->log!=NULL)) {
  1738.                     HTS_LOG(opt,LOG_DEBUG); fprintf(opt->log,"(Real Media): detected %s"LF,line); test_flush;
  1739.                   }
  1740.                 }
  1741.               }
  1742.               fclose(fp);
  1743.             }
  1744.           }
  1745.         } else */
  1746.  
  1747.  
  1748.         /* External modules */
  1749.         if ( opt->parsejava && ( opt->parsejava & HTSPARSE_NO_CLASS ) == 0 && fexist(savename)) {
  1750.           char BIGSTK buff_err_msg[1024];
  1751.           htsmoduleStruct BIGSTK str;
  1752.           buff_err_msg[0] = '\0';
  1753.           memset(&str, 0, sizeof(str));
  1754.           /* */
  1755.           str.err_msg = buff_err_msg;
  1756.           str.filename = savename;
  1757.           str.mime = r.contenttype;
  1758.           str.url_host = urladr;
  1759.           str.url_file = urlfil;
  1760.           str.size = (int) r.size;
  1761.           /* */
  1762.           str.addLink = htsAddLink;
  1763.           /* */
  1764.           str.liens = liens;
  1765.           str.opt = opt;
  1766.           str.sback = sback;
  1767.           str.cache = &cache;
  1768.           str.hashptr = hashptr;
  1769.           str.numero_passe = numero_passe;
  1770.           str.add_tab_alloc = add_tab_alloc;
  1771.           /* */
  1772.           str.lien_tot_ = &lien_tot;
  1773.           str.ptr_ = &ptr;
  1774.           str.lien_size_ = &lien_size;
  1775.           str.lien_buffer_ = &lien_buffer;
  1776.           /* Parse if recognized */
  1777.           switch(hts_parse_externals(&str)) {
  1778.           case 1:
  1779.             if ((opt->debug>1) && (opt->log!=NULL)) {
  1780.               HTS_LOG(opt,LOG_DEBUG); fprintf(opt->log,"(External module): parsed successfully %s"LF,savename); test_flush;
  1781.             }
  1782.             break;
  1783.           case 0:
  1784.             if ((opt->debug>1) && (opt->log!=NULL)) {
  1785.               HTS_LOG(opt,LOG_DEBUG); fprintf(opt->log,"(External module): couldn't parse successfully %s : %s"LF,savename, str.err_msg); test_flush;
  1786.             }
  1787.             break;
  1788.           }
  1789.         }
  1790.              
  1791.         
  1792.       }  // text/html ou autre
  1793.       
  1794.  
  1795.       /* Post-processing */
  1796.       if (fexist(savename)) {
  1797.         usercommand(opt, 0, NULL, savename, urladr, urlfil);
  1798.       }
  1799.  
  1800.     }  // if !error
  1801.  
  1802. jump_if_done:
  1803.     // libΘrer les liens
  1804.     if (r.adr) { 
  1805.       freet(r.adr); 
  1806.       r.adr=NULL; 
  1807.     }   // libΘrer la mΘmoire!
  1808.     
  1809.     // prochain lien
  1810.     ptr++;
  1811.     
  1812.     // faut-il sauter le(s) lien(s) suivant(s)? (fichiers images α passer aprΦs les html)
  1813.     if (opt->getmode & 4) {    // sauver les non html aprΦs
  1814.       // sauter les fichiers selon la passe
  1815.       if (!numero_passe) {
  1816.         while((ptr<lien_tot)?(   liens[ptr]->pass2):0) ptr++;
  1817.       } else {
  1818.         while((ptr<lien_tot)?( ! liens[ptr]->pass2):0) ptr++;
  1819.       }
  1820.       if (ptr>=lien_tot) {     // fin de boucle
  1821.         if (!numero_passe) { // premiΦre boucle
  1822.           if ((opt->debug>1) && (opt->log!=NULL)) {
  1823.             fprintf(opt->log,LF"Now getting non-html files..."LF);
  1824.             test_flush;
  1825.           }
  1826.           numero_passe=1;   // seconde boucle
  1827.           ptr=0;
  1828.           // prochain pass2
  1829.           while((ptr<lien_tot)?(!liens[ptr]->pass2):0) ptr++;
  1830.           
  1831.           //printf("first link==%d\n");
  1832.           
  1833.         }
  1834.       }  
  1835.     }
  1836.  
  1837.     // copy abort state if necessary from outside
  1838.     //if (!exit_xh && opt->state.exit_xh) {
  1839.     //  exit_xh=opt->state.exit_xh;
  1840.     //}
  1841.     // a-t-on dΘpassΘ le quota?
  1842.     if (!back_checkmirror(opt)) {
  1843.       ptr=lien_tot;
  1844.     } else if (opt->state.exit_xh) {  // sortir
  1845.       if (opt->log) {
  1846.         HTS_LOG(opt,LOG_INFO); 
  1847.         if (opt->state.exit_xh==1) {
  1848.           fprintf(opt->log,"Exit requested by shell or user"LF);
  1849.         } else {
  1850.           fprintf(opt->log,"Exit requested by engine"LF);
  1851.         }
  1852.         test_flush;
  1853.       } 
  1854.       ptr=lien_tot;
  1855.     }
  1856.   } while(ptr<lien_tot);
  1857.   //
  1858.   //
  1859.   //
  1860.   
  1861.   /*
  1862.   Ensure the index is being closed
  1863.   */
  1864.   HT_INDEX_END;
  1865.   
  1866.   /* 
  1867.     updating-a-remotely-deteted-website hack
  1868.     no much data transfered, no data saved
  1869.     <no files successfulyl saved>
  1870.     we assume that something was bad (no connection)
  1871.     just backup old cache and restore everything
  1872.   */
  1873.   if (
  1874.     (HTS_STAT.stat_files <= 0) 
  1875.     && 
  1876.     (HTS_STAT.HTS_TOTAL_RECV < 32768)    /* should be fine */
  1877.     ) {
  1878.     if (opt->log) {
  1879.       HTS_LOG(opt,LOG_INFO); fprintf(opt->log,"No data seems to have been transfered during this session! : restoring previous one!"LF);
  1880.       test_flush;
  1881.     } 
  1882.     XH_uninit;
  1883.     if ( (fexist(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/old.dat"))) && (fexist(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/old.ndx"))) ) {
  1884.       remove(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/new.dat"));
  1885.       remove(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/new.ndx"));
  1886.       remove(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/new.lst"));
  1887.       remove(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/new.txt"));
  1888.       rename(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/old.dat"),fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/new.dat"));
  1889.       rename(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/old.ndx"),fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/new.ndx"));
  1890.       rename(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/old.lst"),fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/new.lst"));
  1891.       rename(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/old.txt"),fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/new.txt"));
  1892.     }
  1893.     opt->state.exit_xh=2;        /* interrupted (no connection detected) */
  1894.     return 1;
  1895.   }
  1896.  
  1897.   // info text  
  1898.   if (cache.txt) {
  1899.     fclose(cache.txt); cache.txt=NULL;
  1900.   }
  1901.  
  1902.   // purger!
  1903.   if (cache.lst) {
  1904.     fclose(cache.lst); cache.lst=NULL;
  1905.     if (opt->delete_old) {
  1906.       FILE *old_lst,*new_lst;
  1907.       //
  1908.       opt->state._hts_in_html_parsing=3;
  1909.       //
  1910.       old_lst=fopen(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/old.lst"),"rb");
  1911.       if (old_lst) {
  1912.         off_t sz=fsize(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/new.lst"));
  1913.         new_lst=fopen(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_log),"hts-cache/new.lst"),"rb");
  1914.         if ((new_lst) && (sz>0)) {
  1915.           char* adr=(char*) malloct(sz);
  1916.           if (adr) {
  1917.             if (fread(adr,1,sz,new_lst) == sz) {
  1918.               char line[1100];
  1919.               int purge=0;
  1920.               while(!feof(old_lst)) {
  1921.                 linput(old_lst,line,1000);
  1922.                 if (!strstr(adr,line)) {    // fichier non trouvΘ dans le nouveau?
  1923.                   char BIGSTK file[HTS_URLMAXSIZE*2];
  1924.                   strcpybuff(file,StringBuff(opt->path_html));
  1925.                   strcatbuff(file,line+1);
  1926.                   file[strlen(file)-1]='\0';
  1927.                   if (fexist(file)) {       // toujours sur disque: virer
  1928.                     if (opt->log) {
  1929.                       HTS_LOG(opt,LOG_INFO); fprintf(opt->log,"Purging %s"LF,file);
  1930.                     }
  1931.                     remove(file); purge=1;
  1932.                   }
  1933.                 }
  1934.               }
  1935.               {
  1936.                 fseek(old_lst,0,SEEK_SET);
  1937.                 while(!feof(old_lst)) {
  1938.                   linput(old_lst,line,1000);
  1939.                   while(strnotempty(line) && (line[strlen(line)-1]!='/') && (line[strlen(line)-1]!='\\')) {
  1940.                     line[strlen(line)-1]='\0';
  1941.                   }
  1942.                   if (strnotempty(line))
  1943.                     line[strlen(line)-1]='\0';
  1944.                   if (strnotempty(line))
  1945.                     if (!strstr(adr,line)) {    // non trouvΘ?
  1946.                       char BIGSTK file[HTS_URLMAXSIZE*2];
  1947.                       strcpybuff(file,StringBuff(opt->path_html));
  1948.                       strcatbuff(file,line+1);
  1949.                       while ((strnotempty(file)) && (rmdir(file)==0)) {    // ok, ΘliminΘ (existait)
  1950.                         purge=1;
  1951.                         if (opt->log) {
  1952.                           HTS_LOG(opt,LOG_INFO); fprintf(opt->log,"Purging directory %s/"LF,file);
  1953.                           while(strnotempty(file) && (file[strlen(file)-1]!='/') && (file[strlen(file)-1]!='\\')) {
  1954.                             file[strlen(file)-1]='\0';
  1955.                           }
  1956.                           if (strnotempty(file))
  1957.                             file[strlen(file)-1]='\0';
  1958.                         }
  1959.                       }
  1960.                     }
  1961.                 }
  1962.               }
  1963.               //
  1964.               if (!purge) {
  1965.                 if (opt->log) {
  1966.                   fprintf(opt->log,"No files purged"LF);
  1967.                 }
  1968.               }
  1969.             }
  1970.             freet(adr);
  1971.           }
  1972.           fclose(new_lst);
  1973.         }
  1974.         fclose(old_lst);
  1975.       }
  1976.       //
  1977.       opt->state._hts_in_html_parsing=0;
  1978.     }
  1979.   }
  1980.   // fin purge!
  1981.  
  1982.   // Indexation
  1983.   if (opt->kindex)
  1984.     index_finish(StringBuff(opt->path_html),opt->kindex);
  1985.  
  1986.   // afficher rΘsumΘ dans log
  1987.   if (opt->log!=NULL) {
  1988.     char BIGSTK finalInfo[8192];
  1989.     int error   = fspc(opt,NULL,"error");
  1990.     int warning = fspc(opt,NULL,"warning");
  1991.     int info    = fspc(opt,NULL,"info");
  1992.     char BIGSTK htstime[256];
  1993.     char BIGSTK infoupdated[256];
  1994.     // int n=(int) (stat_loaded/(time_local()-HTS_STAT.stat_timestart));
  1995.     LLint n=(LLint) (HTS_STAT.HTS_TOTAL_RECV/(max(1,time_local()-HTS_STAT.stat_timestart)));
  1996.     
  1997.     sec2str(htstime,time_local()-HTS_STAT.stat_timestart);
  1998.     //sprintf(finalInfo + strlen(finalInfo),LF"HTS-mirror complete in %s : %d links scanned, %d files written (%d bytes overall) [%d bytes received at %d bytes/sec]"LF,htstime,lien_tot-1,HTS_STAT.stat_files,stat_bytes,stat_loaded,n);
  1999.     infoupdated[0] = '\0';
  2000.     if (opt->is_update) {
  2001.       if (HTS_STAT.stat_updated_files > 0) {
  2002.         sprintf(infoupdated, ", %d files updated", (int)HTS_STAT.stat_updated_files);
  2003.       } else {
  2004.         sprintf(infoupdated, ", no files updated");
  2005.       }
  2006.     }
  2007.     finalInfo[0] = '\0';
  2008.     sprintf(finalInfo + strlen(finalInfo),
  2009.       "HTTrack Website Copier/"HTTRACK_VERSION" mirror complete in %s : "
  2010.       "%d links scanned, %d files written ("LLintP" bytes overall)%s "
  2011.       "["LLintP" bytes received at "LLintP" bytes/sec]",
  2012.       htstime,
  2013.       (int)lien_tot-1,
  2014.       (int)HTS_STAT.stat_files,
  2015.       (LLint)HTS_STAT.stat_bytes,
  2016.       infoupdated,
  2017.       (LLint)HTS_STAT.HTS_TOTAL_RECV,
  2018.       (LLint)n
  2019.       );
  2020.  
  2021.     if (HTS_STAT.total_packed > 0 && HTS_STAT.total_unpacked > 0) {
  2022.       int packed_ratio=(int)((LLint)(HTS_STAT.total_packed*100)/HTS_STAT.total_unpacked);
  2023.       sprintf(finalInfo + strlen(finalInfo),", "LLintP" bytes transfered using HTTP compression in %d files, ratio %d%%",(LLint)HTS_STAT.total_unpacked,HTS_STAT.total_packedfiles,(int)packed_ratio);
  2024.     }
  2025.     if (!opt->nokeepalive && HTS_STAT.stat_sockid > 0 && HTS_STAT.stat_nrequests > HTS_STAT.stat_sockid) {
  2026.       int rq = (HTS_STAT.stat_nrequests * 10) / HTS_STAT.stat_sockid;
  2027.       sprintf(finalInfo + strlen(finalInfo),", %d.%d requests per connection", rq/10, rq%10);
  2028.     }
  2029.     sprintf(finalInfo + strlen(finalInfo),LF);
  2030.     if (error)
  2031.       sprintf(finalInfo + strlen(finalInfo),"(%d errors, %d warnings, %d messages)"LF,error,warning,info);
  2032.     else
  2033.       sprintf(finalInfo + strlen(finalInfo),"(No errors, %d warnings, %d messages)"LF,warning,info);
  2034.  
  2035.     // Log
  2036.     fprintf(opt->log,LF"%s", finalInfo);
  2037.  
  2038.     // Close ZIP
  2039.     if (cache.zipOutput) {
  2040.       zipClose(cache.zipOutput, finalInfo);
  2041.       cache.zipOutput = NULL;
  2042.     }
  2043.     
  2044.     test_flush;
  2045.   }
  2046. #if DEBUG_HASH
  2047.   // noter les collisions
  2048.   {
  2049.     int i;
  2050.     int empty1=0,empty2=0,empty3=0;
  2051.     for(i=0;i<HTS_HASH_SIZE;i++) {
  2052.       if (hash.hash[0][i] == -1)
  2053.         empty1++;
  2054.       if (hash.hash[1][i] == -1)
  2055.         empty2++;
  2056.       if (hash.hash[2][i] == -1)
  2057.         empty3++;
  2058.     }
  2059.     printf("\n");
  2060.     printf("Debug info: Hash-table report\n");
  2061.     printf("Number of files entered:   %d\n",hashnumber);
  2062.     printf("Table size:                %d\n",HTS_HASH_SIZE);
  2063.     printf("\n");
  2064.     printf("Longest chain sav:              %d, empty: %d\n",longest_hash[0],empty1);
  2065.     printf("Longest chain adr,fil:          %d, empty: %d\n",longest_hash[1],empty2);
  2066.     printf("Longest chain former_adr/fil:   %d, empty: %d\n",longest_hash[2],empty3);
  2067.     printf("\n");
  2068.   }
  2069. #endif    
  2070.   // fin afficher rΘsumΘ dans log
  2071.  
  2072.   // ending
  2073.   usercommand(opt,0,NULL,NULL,NULL,NULL);
  2074.  
  2075.   // dΘsallocation mΘmoire & buffers
  2076.   XH_uninit;
  2077.  
  2078.   return 1;    // OK
  2079. }
  2080. // version 2 pour le reste
  2081. // flusher si on doit lire peu α peu le fichier
  2082. #undef test_flush
  2083. #define test_flush if (opt->flush) { fflush(opt->log); fflush(opt->log); }
  2084.  
  2085.  
  2086. // Estimate transfer rate
  2087. // a little bit complex, but not too much
  2088. /*
  2089.   .. : idle
  2090.   ^  : event
  2091.  
  2092.   ----|----|----|----|----|----|----|----|---->
  2093.    1    2    3    4    5    6    7    8    9   time (seconds)
  2094.   ----|----|----|----|----|----|----|----|---->
  2095.   ^........^.........^.........^.........^.... timer 0
  2096.   ----^.........^.........^.........^......... timer 1
  2097.            0    1    0    1    0    1    0     timer N sets its statistics
  2098.       *         *         *         *          timer 0 resync timer 1
  2099.  
  2100.   Therefore, each seconds, we resync the transfer rate with 2-seconds
  2101.  
  2102. */
  2103. int engine_stats(void) {
  2104. #if 0
  2105.   static FILE* debug_fp=NULL; /* ok */
  2106.   if (!debug_fp)
  2107.     debug_fp=fopen("esstat.txt","wb");
  2108. #endif
  2109.   HTS_STAT.stat_nsocket=HTS_STAT.stat_errors=HTS_STAT.nbk=0;
  2110.   HTS_STAT.nb=0;
  2111.   if (HTS_STAT.HTS_TOTAL_RECV>2048) {
  2112.     TStamp cdif=mtime_local();
  2113.     int i;
  2114.  
  2115.     for(i=0;i<2;i++) {
  2116.       if ( (cdif - HTS_STAT.istat_timestart[i]) >= 2000) {
  2117.         TStamp dif;
  2118. #if 0
  2119. fprintf(debug_fp,"set timer %d\n",i); fflush(debug_fp);
  2120. #endif
  2121.         dif=cdif - HTS_STAT.istat_timestart[i];
  2122.         if ((TStamp)(dif/1000)>0) {
  2123.           LLint byt=(HTS_STAT.HTS_TOTAL_RECV - HTS_STAT.istat_bytes[i]);
  2124.           HTS_STAT.rate=(LLint)((TStamp) ((TStamp)byt/(dif/1000)));
  2125.           HTS_STAT.istat_idlasttimer=i;      // this timer recently sets the stats
  2126.           //
  2127.           HTS_STAT.istat_bytes[i]=HTS_STAT.HTS_TOTAL_RECV;
  2128.           HTS_STAT.istat_timestart[i]=cdif;
  2129.         }
  2130.         return 1;       /* refreshed */
  2131.       }
  2132.     }
  2133.  
  2134.     // resynchronization between timer 0 (master) and 1 (slave)
  2135.     // timer #0 resync timer #1 when reaching 1 second limit
  2136.     if (HTS_STAT.istat_reference01 != HTS_STAT.istat_timestart[0]) {
  2137.       if ( (cdif - HTS_STAT.istat_timestart[0]) >= 1000) {
  2138. #if 0
  2139. fprintf(debug_fp,"resync timer 1\n"); fflush(debug_fp);
  2140. #endif
  2141.         HTS_STAT.istat_bytes[1]=HTS_STAT.HTS_TOTAL_RECV;
  2142.         HTS_STAT.istat_timestart[1]=cdif;
  2143.         HTS_STAT.istat_reference01=HTS_STAT.istat_timestart[0];
  2144.       }
  2145.     }
  2146.  
  2147.   }
  2148.   return 0;
  2149. }
  2150.  
  2151.  
  2152. #define _FILTERS     (*opt->filters.filters)
  2153. #define _FILTERS_PTR (opt->filters.filptr)
  2154. #define _ROBOTS      ((robots_wizard*)opt->robotsptr)
  2155.  
  2156. // bannir host (trop lent etc)
  2157. void host_ban(httrackp* opt,lien_url** liens,int ptr,int lien_tot,struct_back* sback,char* host) {
  2158.   lien_back* const back = sback->lnk;
  2159.   const int back_max = sback->count;
  2160.   //int l;
  2161.   int i;
  2162.  
  2163.   if (host[0]=='!')
  2164.     return;    // erreur.. dΘja cancellΘ.. bizarre.. devrait pas arriver
  2165.  
  2166.   /* sanity check */
  2167.   if (*_FILTERS_PTR + 1 >= opt->maxfilter) {
  2168.     opt->maxfilter += HTS_FILTERSINC;
  2169.     if (filters_init(&_FILTERS, opt->maxfilter, HTS_FILTERSINC) == 0) {
  2170.       printf("PANIC! : Too many filters : >%d [%d]\n",*_FILTERS_PTR,__LINE__);
  2171.       if (opt->log) {
  2172.         fprintf(opt->log,LF"Too many filters, giving up..(>%d)"LF,*_FILTERS_PTR);
  2173.         fprintf(opt->log,"To avoid that: use #F option for more filters (example: -#F5000)"LF);
  2174.         fflush(opt->log);
  2175.       }
  2176.       assertf("too many filters - giving up" == NULL);
  2177.     }
  2178.   }
  2179.  
  2180.   // interdire host
  2181.   assertf((*_FILTERS_PTR) < opt->maxfilter);
  2182.   if (*_FILTERS_PTR < opt->maxfilter) {
  2183.     strcpybuff(_FILTERS[*_FILTERS_PTR],"-");
  2184.     strcatbuff(_FILTERS[*_FILTERS_PTR],host);
  2185.     strcatbuff(_FILTERS[*_FILTERS_PTR],"/*");     // host/ * interdit
  2186.     (*_FILTERS_PTR)++; 
  2187.   }
  2188.   
  2189.   // oups
  2190.   if (strlen(host)<=1) {    // euhh?? longueur <= 1
  2191.     if (strcmp(host,"file://")) {
  2192.       //## if (host[0]!=lOCAL_CHAR) {  // pas local
  2193.       if (opt->log!=NULL) {
  2194.         fprintf(opt->log,"PANIC! HostCancel detected memory leaks [char %d]"LF,host[0]); test_flush;
  2195.       }          
  2196.       return;  // purΘe
  2197.     }
  2198.   }
  2199.   
  2200.   // couper connexion
  2201.   for(i=0;i<back_max;i++) {
  2202.     if (back[i].status>=0)    // rΘception OU prΩt
  2203.       if (strfield2(back[i].url_adr,host)) {
  2204. #if HTS_DEBUG_CLOSESOCK
  2205.         DEBUG_W("host control: deletehttp\n");
  2206. #endif
  2207.         back[i].status=0;  // terminΘ
  2208.         back_set_finished(sback, i);
  2209.         if (back[i].r.soc!=INVALID_SOCKET) deletehttp(&back[i].r);
  2210.         back[i].r.soc=INVALID_SOCKET;
  2211.         back[i].r.statuscode=STATUSCODE_TIMEOUT;    // timeout (peu importe si c'est un traffic jam)
  2212.         strcpybuff(back[i].r.msg,"Link Cancelled by host control");
  2213.         
  2214.         if ((opt->debug>1) && (opt->log!=NULL)) {
  2215.           fprintf(opt->log,"Shutdown: %s%s"LF,back[i].url_adr,back[i].url_fil); test_flush;
  2216.         }          
  2217.       }
  2218.   }
  2219.   
  2220.   // effacer liens
  2221.   //l=strlen(host);
  2222.   for(i=0;i<lien_tot;i++) {
  2223.     //if (liens[i]->adr_len==l) {    // mΩme taille de chaεne
  2224.     // Calcul de taille sΘcurisΘe
  2225.     if (liens[i]) {
  2226.       if (liens[i]->adr) {
  2227.         int l = 0;
  2228.         while((liens[i]->adr[l]) && (l<1020)) l++;
  2229.         if ((l > 0) && (l<1020)) {   // sΘcuritΘ
  2230.           if (strfield2(jump_identification(liens[i]->adr),host)) {    // host
  2231.             if ((opt->debug>1) && (opt->log!=NULL)) {
  2232.               fprintf(opt->log,"Cancel: %s%s"LF,liens[i]->adr,liens[i]->fil); test_flush;
  2233.             }
  2234.             strcpybuff(liens[i]->adr,"!");    // cancel (invalide hash)
  2235.             // on efface pas le hash, because si on rencontre le lien, reverif sav..
  2236.           }
  2237.         } else {
  2238.           if (opt->log!=NULL) {
  2239.             char dmp[1040];
  2240.             dmp[0]='\0';
  2241.             strncatbuff(dmp,liens[i]->adr,1024);
  2242.             fprintf(opt->log,"WARNING! HostCancel detected memory leaks [len %d at %d]"LF,l,i); test_flush;
  2243.             fprintf(opt->log,"dump 1024 bytes (address %p): "LF"%s"LF,liens[i]->adr,dmp); test_flush;
  2244.           }          
  2245.         }
  2246.       } else {
  2247.         if (opt->log!=NULL) {
  2248.           fprintf(opt->log,"WARNING! HostCancel detected memory leaks [adr at %d]"LF,i); test_flush;
  2249.         }  
  2250.       }
  2251.     } else {
  2252.       if (opt->log!=NULL) {
  2253.         fprintf(opt->log,"WARNING! HostCancel detected memory leaks [null at %d]"LF,i); test_flush;
  2254.       }  
  2255.     }
  2256.     //}
  2257.   }
  2258. }
  2259.  
  2260. int filters_init(char*** ptrfilters, int maxfilter, int filterinc) {
  2261.   char** filters = *ptrfilters;
  2262.   int filter_max=maximum(maxfilter, 128);
  2263.   if (filters == NULL) {
  2264.     filters=(char**) malloct( sizeof(char*) * (filter_max+2) );
  2265.     memset(filters, 0, sizeof(char*) * (filter_max+2));  // filters[0] == 0
  2266.   } else {
  2267.     filters=(char**) realloct(filters, sizeof(char*) * (filter_max+2) );
  2268.   }
  2269.   if (filters) {
  2270.     if (filters[0] == NULL) {
  2271.       filters[0]=(char*) malloct( sizeof(char) * (filter_max+2) * (HTS_URLMAXSIZE*2) );
  2272.       memset(filters[0], 0, sizeof(char) * (filter_max+2) * (HTS_URLMAXSIZE*2) );
  2273.     } else {
  2274.       filters[0]=(char*) realloct(filters[0], sizeof(char) * (filter_max+2) * (HTS_URLMAXSIZE*2) );
  2275.     }
  2276.     if (filters[0] == NULL) {
  2277.       freet(filters);
  2278.       filters = NULL;
  2279.     }
  2280.   }
  2281.   if (filters != NULL) {
  2282.     int i;
  2283.     int from;
  2284.     if (filterinc == 0)
  2285.       from = 0;
  2286.     else
  2287.       from = filter_max - filterinc;
  2288.     for(i=0 ; i<=filter_max ; i++) {    // PLUS UN (sΘcuritΘ)
  2289.       filters[i]=filters[0]+i*(HTS_URLMAXSIZE*2);
  2290.     }
  2291.     for(i=from ; i<=filter_max ; i++) {    // PLUS UN (sΘcuritΘ)
  2292.       filters[i][0]='\0';    // clear
  2293.     }
  2294.   }
  2295.   *ptrfilters = filters;
  2296.   return (filters != NULL) ? filter_max : 0;
  2297. }
  2298.  
  2299. static int mkdir_compat(const char *pathname) {
  2300. #ifdef _WIN32
  2301.   return mkdir(pathname);
  2302. #else    
  2303.   return mkdir(pathname, HTS_ACCESS_FOLDER);
  2304. #endif
  2305. }
  2306.  
  2307. /* path must end with "/" or with the finename (/tmp/bar/ or /tmp/bar/foo.zip) */
  2308. HTSEXT_API int dir_exists(const char* path) {
  2309.   struct stat st;
  2310.   char BIGSTK file[HTS_URLMAXSIZE*2];
  2311.   int i = 0;
  2312.   if (strnotempty(path) == 0) {
  2313.     errno = EINVAL;
  2314.         return 0;
  2315.   }
  2316.   if (strlen(path) > HTS_URLMAXSIZE) {
  2317.     errno = EINVAL;
  2318.         return 0;
  2319.   }
  2320.  
  2321.   /* Get a copy */
  2322.   strcpybuff(file, path);
  2323. #ifdef _WIN32
  2324.   /* To system name */
  2325.   for(i = 0 ; file[i] != 0 ; i++) {
  2326.     if (file[i] == '/') {
  2327.       file[i] = PATH_SEPARATOR;
  2328.     }
  2329.   }
  2330. #endif
  2331.   /* Get prefix (note: file can not be empty here) */
  2332.   for(i = (int) strlen(file) - 1 ; i > 0 && file[i] != PATH_SEPARATOR ; i--);
  2333.   for( ; i > 0 && file[i] == PATH_SEPARATOR ; i--);
  2334.   file[i + 1] = '\0';
  2335.  
  2336.   /* Check the final dir */
  2337.   if (stat(file, &st) == 0 && S_ISDIR(st.st_mode)) {
  2338.     errno = 0;
  2339.     return 1;   /* EXISTS */
  2340.   }
  2341.   errno = 0;
  2342.   return 0;   /* DOES NOT EXISTS */
  2343. }
  2344.  
  2345. /* path must end with "/" or with the finename (/tmp/bar/ or /tmp/bar/foo.zip) */
  2346. HTSEXT_API int structcheck(const char* path) {
  2347.   struct stat st;
  2348.   char BIGSTK tmpbuf[HTS_URLMAXSIZE*2];
  2349.   char BIGSTK file[HTS_URLMAXSIZE*2];
  2350.   int i = 0;
  2351.   int npaths;
  2352.   if (strnotempty(path) == 0)
  2353.         return 0;
  2354.   if (strlen(path) > HTS_URLMAXSIZE) {
  2355.     errno = EINVAL;
  2356.         return -1;
  2357.   }
  2358.  
  2359.   /* Get a copy */
  2360.   strcpybuff(file, path);
  2361. #ifdef _WIN32
  2362.   /* To system name */
  2363.   for(i = 0 ; file[i] != 0 ; i++) {
  2364.     if (file[i] == '/') {
  2365.       file[i] = PATH_SEPARATOR;
  2366.     }
  2367.   }
  2368. #endif
  2369.   /* Get prefix (note: file can not be empty here) */
  2370.   for(i = (int) strlen(file) - 1 ; i > 0 && file[i] != PATH_SEPARATOR ; i--);
  2371.   for( ; i > 0 && file[i] == PATH_SEPARATOR ; i--);
  2372.   file[i + 1] = '\0';
  2373.  
  2374.   /* First check the final dir */
  2375.   if (stat(file, &st) == 0 && S_ISDIR(st.st_mode)) {
  2376.     return 0;   /* OK */
  2377.   }
  2378.  
  2379.   /* Start from the begining */
  2380.   i = 0;
  2381.  
  2382.   /* Skip irrelevant part (the root slash, or the drive path) */
  2383. #ifdef _WIN32
  2384.   if (file[0] != 0 && file[1] == ':') {  /* f:\ */
  2385.     i+= 2;
  2386.     if (file[i] == PATH_SEPARATOR) {  /* f:\ */
  2387.       i++;
  2388.     }
  2389.   } else if (file[0] == PATH_SEPARATOR && file[1] == PATH_SEPARATOR) {    /* \\mch */
  2390.     i+= 2;
  2391.   }
  2392. #endif
  2393.  
  2394.   /* Check paths */
  2395.   for(npaths = 1 ; ; npaths++) {
  2396.     char end_char;
  2397.  
  2398.     /* Go to next path */
  2399.  
  2400.     /* Skip separator(s) */
  2401.     for( ; file[i] == PATH_SEPARATOR ; i++);
  2402.     /* Next separator */
  2403.     for( ; file[i] != 0 && file[i] != PATH_SEPARATOR ; i++);
  2404.  
  2405.     /* Check */
  2406.     end_char = file[i];
  2407.     if (end_char != 0) {
  2408.       file[i] = '\0';
  2409.     }
  2410.     if (stat(file, &st) == 0) {   /* Something exists */
  2411.       if (!S_ISDIR(st.st_mode)) {
  2412. #if HTS_REMOVE_ANNOYING_INDEX
  2413.         if (S_ISREG(st.st_mode)) {   /* Regular file in place ; move it and create directory */
  2414.           sprintf(tmpbuf, "%s.txt", file);
  2415.           if (rename(file, tmpbuf) != 0) {    /* Can't rename regular file */
  2416.             return -1;
  2417.           }
  2418.           if (mkdir_compat(file) != 0) {      /* Can't create directory */
  2419.             return -1;
  2420.           }
  2421.         }
  2422. #else
  2423. #error Not implemented
  2424. #endif
  2425.       }
  2426.     } else {      /* Nothing exists ; create directory */
  2427.       if (mkdir_compat(file) != 0) {      /* Can't create directory */
  2428.         return -1;
  2429.       }
  2430.     }
  2431.     if (end_char == 0) {       /* End */
  2432.       break;
  2433.     } else {
  2434.       file[i] = end_char;      /* Restore / */
  2435.     }
  2436.   }
  2437.   return 0;
  2438. }
  2439.  
  2440. // sauver un fichier
  2441. int filesave(httrackp* opt,const char* adr,int len,const char* s,const char* url_adr,const char* url_fil) {
  2442.   FILE* fp;
  2443.   // Θcrire le fichier
  2444.   if ((fp = filecreate(&opt->state.strc, s))!=NULL) {
  2445.     int nl=0;
  2446.     if (len>0) {
  2447.       nl=(int) fwrite(adr,1,len,fp);
  2448.     }
  2449.     fclose(fp);
  2450.     if (nl!=len)  // erreur
  2451.       return -1;
  2452.   } else
  2453.     return -1;
  2454.   
  2455.   return 0;
  2456. }
  2457.  
  2458. /* We should stop */
  2459. int check_fatal_io_errno(void) {
  2460.   switch(errno) {
  2461. #ifdef EMFILE
  2462.   case EMFILE: /* Too many open files */
  2463. #endif
  2464. #ifdef ENOSPC
  2465.   case ENOSPC: /* No space left on device */
  2466. #endif
  2467. #ifdef EROFS
  2468.   case EROFS:  /* Read-only file system */
  2469. #endif
  2470.     return 1;
  2471.     break;
  2472.   }
  2473.   return 0;
  2474. }
  2475.  
  2476.  
  2477. // ouvrir un fichier (avec chemin Un*x)
  2478. FILE* filecreate(filenote_strc *strc, const char* s) {
  2479.   char BIGSTK fname[HTS_URLMAXSIZE*2];
  2480.   FILE* fp;
  2481.   int last_errno = 0;
  2482.   fname[0]='\0';
  2483.  
  2484.   // noter lst
  2485.     if (strc != NULL) {
  2486.         filenote(strc, s, NULL);
  2487.     }
  2488.   
  2489.   strcpybuff(fname, s);
  2490. #if HTS_DOSNAME
  2491.   // remplacer / par des slash arriΦre
  2492.   {
  2493.     int i=0;
  2494.     while(fname[i]) {
  2495.       if (fname[i]=='/')
  2496.         fname[i]='\\';
  2497.       i++;
  2498.     } 
  2499.   } 
  2500.   // a partir d'ici le slash devient antislash
  2501. #endif
  2502.   
  2503.   /* Try to open the file */
  2504.   fp = fopen(fname, "wb");
  2505.  
  2506.   /* Error ? Check the directory structure and retry. */
  2507.   if (fp == NULL) {
  2508.     last_errno = errno;
  2509.     if (structcheck(s) != 0) {
  2510.       last_errno = errno;
  2511.     } else {
  2512.       last_errno = 0;
  2513.     }
  2514.     fp = fopen(fname, "wb");
  2515.   }
  2516.   if (fp == NULL && last_errno != 0) {
  2517.     errno = last_errno;
  2518.   }
  2519. #ifndef _WIN32
  2520.   if (fp != NULL)
  2521.         chmod(fname, HTS_ACCESS_FILE);
  2522. #endif
  2523.   return fp;
  2524. }
  2525.  
  2526. // ouvrir un fichier (avec chemin Un*x)
  2527. FILE* fileappend(filenote_strc *strc,const char* s) {
  2528.   char BIGSTK fname[HTS_URLMAXSIZE*2];
  2529.   FILE* fp;
  2530.   fname[0]='\0';
  2531.  
  2532.   // noter lst
  2533.   filenote(strc,s,NULL);
  2534.   
  2535.   // if (*s=='/') strcpybuff(fname,s+1); else strcpybuff(fname,s);    // pas de / (root!!) // ** SIIIIIII!!! α cause de -O <path>
  2536.   strcpybuff(fname,s);
  2537.  
  2538. #if HTS_DOSNAME
  2539.   // remplacer / par des slash arriΦre
  2540.   {
  2541.     int i=0;
  2542.     while(fname[i]) {
  2543.       if (fname[i]=='/')
  2544.         fname[i]='\\';
  2545.       i++;
  2546.     } 
  2547.   } 
  2548.   // a partir d'ici le slash devient antislash
  2549. #endif
  2550.   
  2551.   // ouvrir
  2552.   fp=fopen(fname,"ab");
  2553.   
  2554. #ifndef _WIN32
  2555.   if (fp!=NULL) chmod(fname,HTS_ACCESS_FILE);
  2556. #endif
  2557.  
  2558.   return fp;
  2559. }
  2560.  
  2561.  
  2562. // create an empty file
  2563. int filecreateempty(filenote_strc *strc, const char* filename) {
  2564.   FILE* fp;
  2565.   fp=filecreate(strc, filename);      // filenote & co
  2566.   if (fp) {
  2567.     fclose(fp);
  2568.     return 1;
  2569.   } else
  2570.     return 0; 
  2571. }
  2572.  
  2573. // noter fichier
  2574. int filenote(filenote_strc *strc, const char* s, filecreate_params* params) {
  2575.   // gestion du fichier liste liste
  2576.   if (params) {
  2577.     //filecreate_params* p = (filecreate_params*) params;
  2578.     strcpybuff(strc->path,params->path);
  2579.     strc->lst=params->lst;
  2580.     return 0;
  2581.   } else if (strc->lst) {
  2582.     char BIGSTK savelst[HTS_URLMAXSIZE*2];
  2583.         char catbuff[CATBUFF_SIZE];
  2584.     strcpybuff(savelst,fslash(catbuff,s));
  2585.     // couper chemin?
  2586.     if (strnotempty(strc->path)) {
  2587.       if (strncmp(fslash(catbuff,strc->path),savelst,strlen(strc->path))==0) {  // couper
  2588.         strcpybuff(savelst,s+strlen(strc->path));
  2589.       }
  2590.     }
  2591.     fprintf(strc->lst,"[%s]"LF,savelst);
  2592.     fflush(strc->lst);
  2593.   }
  2594.   return 1;
  2595. }
  2596.  
  2597. void file_notify(httrackp* opt,const char* adr,const char* fil,const char* save,int create,int modify,int not_updated) {
  2598.   RUN_CALLBACK6(opt, filesave2, adr, fil, save, create, modify, not_updated);
  2599. }
  2600.  
  2601. // executer commande utilisateur
  2602. static void postprocess_file(httrackp* opt, const char* save, const char* adr, const char* fil);
  2603. HTS_INLINE void usercommand(httrackp* opt,int _exe,const char* _cmd,const char* file,const char* adr,const char* fil) {
  2604.     usercommand_strc* strc = &opt->state.usercmd;
  2605.   
  2606.   /* Callback */
  2607.   if (_exe) {
  2608.     strcpybuff(strc->cmd,_cmd);
  2609.     if (strnotempty(strc->cmd))
  2610.       strc->exe=_exe;
  2611.     else
  2612.       strc->exe=0;
  2613.   }
  2614.  
  2615.   /* post-processing */
  2616.   postprocess_file(opt, file, adr, fil);
  2617.  
  2618.     if (file != NULL && strnotempty(file)) {
  2619.     RUN_CALLBACK1(opt, filesave, file);
  2620.     }
  2621.  
  2622.   if (strc->exe) {
  2623.     if (file != NULL && strnotempty(file)) {
  2624.       if (strnotempty(strc->cmd)) {
  2625.         usercommand_exe(strc->cmd,file);
  2626.       }
  2627.     }
  2628.   }
  2629. }
  2630. void usercommand_exe(const char* cmd,const char* file) {
  2631.   char BIGSTK temp[8192];
  2632.   char c[2]="";
  2633.   int i;
  2634.   temp[0]='\0';
  2635.   //
  2636.   for(i=0;i<(int) strlen(cmd);i++) {
  2637.     if ((cmd[i]=='$') && (cmd[i+1]=='0')) {
  2638.       strcatbuff(temp,file);
  2639.       i++;
  2640.     } else {
  2641.       c[0]=cmd[i]; c[1]='\0';
  2642.       strcatbuff(temp,c);
  2643.     }
  2644.   }
  2645.   system(temp);
  2646. }
  2647.  
  2648.  
  2649. static void postprocess_file(httrackp* opt,const char* save, const char* adr, const char* fil) {
  2650.   int first = 0;
  2651.   /* MIME-html archive to build */
  2652.   if (opt != NULL && opt->mimehtml) {
  2653.     if (adr != NULL && strcmp(adr, "primary") == 0) {
  2654.       adr = NULL;
  2655.     }
  2656.     if (save != NULL && opt != NULL && adr != NULL && adr[0] && strnotempty(save) && fexist(save)) {
  2657.       const char* rsc_save = save;
  2658.       const char* rsc_fil = strrchr(fil, '/');
  2659.       int n;
  2660.       if (rsc_fil == NULL)
  2661.         rsc_fil = fil;
  2662.       if (strncmp(fslash(OPT_GET_BUFF(opt),save), fslash(OPT_GET_BUFF(opt),StringBuff(opt->path_html)), (n = (int)strlen(StringBuff(opt->path_html)))) == 0) {
  2663.         rsc_save += n;
  2664.       }
  2665.  
  2666.       if (!opt->state.mimehtml_created) {
  2667.         first = 1;
  2668.         opt->state.mimefp = fopen(fconcat(OPT_GET_BUFF(opt), StringBuff(opt->path_html),"index.mht"), "wb");
  2669.         if (opt->state.mimefp != NULL) {
  2670.           char BIGSTK rndtmp[1024], currtime[256];
  2671.           srand((unsigned int)time(NULL));
  2672.           time_gmt_rfc822(currtime);
  2673.           sprintf(rndtmp, "%d_%d", (int)time(NULL), (int) rand());
  2674.           StringRoom(opt->state.mimemid, 256);
  2675.           sprintf(StringBuffRW(opt->state.mimemid), "----=_MIMEPart_%s_=----", rndtmp);
  2676.           StringSetLength(opt->state.mimemid, -1);
  2677.           fprintf(opt->state.mimefp, "From: HTTrack Website Copier <nobody@localhost>\r\n"
  2678.             "Subject: Local mirror\r\n"
  2679.             "Date: %s\r\n"
  2680.             "Message-ID: <httrack_%s@localhost>\r\n"
  2681.             "Content-Type: multipart/related;\r\n"
  2682.             "\tboundary=\"%s\";\r\n"
  2683.             "\ttype=\"text/html\"\r\n"
  2684.             "MIME-Version: 1.0\r\n"
  2685.             "\r\nThis message is a RFC MIME-compliant multipart message.\r\n"
  2686.             "\r\n"
  2687.             , currtime, rndtmp, StringBuff(opt->state.mimemid));
  2688.           opt->state.mimehtml_created = 1;
  2689.         } else {
  2690.           opt->state.mimehtml_created = -1;
  2691.           if ( opt->log != NULL ) {
  2692.             HTS_LOG(opt,LOG_ERROR); fprintf(opt->log,"unable to create index.mht"LF);
  2693.           }
  2694.         }
  2695.       }
  2696.       if (opt->state.mimehtml_created == 1 && opt->state.mimefp != NULL) {
  2697.         FILE* fp = fopen(save, "rb");
  2698.         if (fp != NULL) {
  2699.           char buff[60*100 + 2];
  2700.           char mimebuff[256];
  2701.           char BIGSTK cid[HTS_URLMAXSIZE*3];
  2702.           size_t len;
  2703.           int isHtml = ( ishtml(opt,save) == 1 );
  2704.           mimebuff[0] = '\0';
  2705.  
  2706.           /* CID */
  2707.           strcpybuff(cid, adr);
  2708.           strcatbuff(cid, fil);
  2709.           escape_in_url(cid);
  2710.           { char* a = cid; while((a = strchr(a, '%'))) { *a = 'X'; a++; } }
  2711.           
  2712.           guess_httptype(opt,mimebuff, save);
  2713.           fprintf(opt->state.mimefp, "--%s\r\n", StringBuff(opt->state.mimemid));
  2714.           /*if (first)
  2715.           fprintf(opt->state.mimefp, "Content-disposition: inline\r\n");
  2716.           else*/
  2717.           fprintf(opt->state.mimefp, "Content-disposition: attachment; filename=\"%s\"\r\n", rsc_save);
  2718.           fprintf(opt->state.mimefp, 
  2719.             "Content-Type: %s\r\n"
  2720.             "Content-Transfer-Encoding: %s\r\n"
  2721.             /*"Content-Location: http://localhost/%s\r\n"*/
  2722.             "Content-ID: <%s>\r\n"
  2723.             "\r\n"
  2724.             , mimebuff
  2725.             , isHtml ? "8bit" : "base64"
  2726.             /*, rsc_save*/
  2727.             , cid);
  2728.           while((len = fread(buff, 1, sizeof(buff) - 2, fp)) > 0) {
  2729.             buff[len] = '\0';
  2730.             if (!isHtml) {
  2731.               char base64buff[60*100*2];
  2732.               code64((unsigned char*)buff, (int)len, (unsigned char*)base64buff, 1);
  2733.               fprintf(opt->state.mimefp, "%s", base64buff);
  2734.             } else {
  2735.               fprintf(opt->state.mimefp, "%s", buff);
  2736.             }
  2737.           }
  2738.           fclose(fp);
  2739.           fprintf(opt->state.mimefp, "\r\n\r\n");
  2740.         }
  2741.       }
  2742.     } else if (save == NULL) {
  2743.       if (opt->state.mimehtml_created == 1 && opt->state.mimefp != NULL) {
  2744.         fprintf(opt->state.mimefp, 
  2745.           "--%s--\r\n", StringBuff(opt->state.mimemid));
  2746.         fclose(opt->state.mimefp);
  2747.         opt->state.mimefp = NULL;
  2748.       }
  2749.     }
  2750.   }
  2751. }
  2752.  
  2753. // Θcrire n espaces dans fp
  2754. HTS_INLINE int fspc(httrackp *opt,FILE* fp,const char* type) {
  2755.   fspc_strc* const strc = ( opt != NULL ) ? &opt->state.fspc : NULL;
  2756.   if (fp != NULL) {
  2757.     char s[256];
  2758.     time_t tt;
  2759.     struct tm* A;
  2760.     tt=time(NULL);
  2761.     A=localtime(&tt);
  2762.     if (A == NULL) {
  2763.       int localtime_returned_null=0;
  2764.       assert(localtime_returned_null);
  2765.     }
  2766.     strftime(s,250,"%H:%M:%S",A);
  2767.     if (strnotempty(type))
  2768.             fprintf(fp,"%s\t%c%s: \t",s,hichar(*type),type+1);
  2769.         else
  2770.             fprintf(fp,"%s\t \t",s);
  2771.         if (strc != NULL) {
  2772.             if (strcmp(type,"warning")==0)
  2773.                 strc->warning++;
  2774.             else if (strcmp(type,"error")==0)
  2775.                 strc->error++;
  2776.             else if (strcmp(type,"info")==0)
  2777.                 strc->info++;
  2778.         }
  2779.     } 
  2780.     else if (strc == NULL) {
  2781.         return 0;
  2782.     }
  2783.     else if (!type) {
  2784.         strc->error=strc->warning=strc->info=0;     // reset
  2785.     }
  2786.     else if (strcmp(type,"warning")==0)
  2787.     return strc->warning;
  2788.   else if (strcmp(type,"error")==0)
  2789.     return strc->error;
  2790.   else if (strcmp(type,"info")==0)
  2791.     return strc->info;
  2792.   return 0;
  2793. }
  2794.  
  2795.  
  2796. // vΘrifier taux de transfert
  2797. #if 0
  2798. void check_rate(TStamp stat_timestart,int maxrate) {
  2799.   // vΘrifier taux de transfert (pas trop grand?)
  2800.   /*
  2801.   if (maxrate>0) {
  2802.     int r = (int) (HTS_STAT.HTS_TOTAL_RECV/(time_local()-stat_timestart));    // taux actuel de transfert
  2803.     HTS_STAT.HTS_TOTAL_RECV_STATE=0;
  2804.     if (r>maxrate) {    // taux>taux autorisΘ
  2805.       int taux = (int) (((TStamp) (r - maxrate) * 100) / (TStamp) maxrate);
  2806.       if (taux<15)
  2807.         HTS_STAT.HTS_TOTAL_RECV_STATE=1;   // ralentir un peu (<15% dΘpassement)
  2808.       else if (taux<50)
  2809.         HTS_STAT.HTS_TOTAL_RECV_STATE=2;   // beaucoup (<50% dΘpassement)
  2810.       else
  2811.         HTS_STAT.HTS_TOTAL_RECV_STATE=3;   // ΘnormΘment (>50% dΘpassement)
  2812.     }
  2813.   }
  2814.   */
  2815. }
  2816. #endif
  2817.  
  2818. // ---
  2819. // sous routines liΘes au moteur et au backing
  2820.  
  2821. // supplemental links ready (done) after ptr or ready in background
  2822. int backlinks_done(struct_back* sback,lien_url** liens,int lien_tot,int ptr) {
  2823.   int n=0;
  2824. #if 0
  2825.   int i;
  2826.   //Links done and stored in cache
  2827.   for(i=ptr+1;i<lien_tot;i++) {
  2828.     if (liens[i]) {
  2829.       if (liens[i]->pass2 == -1) {
  2830.         n++;
  2831.       }
  2832.     }
  2833.   }
  2834. #else
  2835.   // finalized in background
  2836.   n+=HTS_STAT.stat_background;
  2837. #endif
  2838.   n+=back_done_incache(sback);
  2839.   return n;
  2840. }
  2841.  
  2842. // remplir backing si moins de max_bytes en mΘmoire
  2843. HTS_INLINE int back_fillmax(struct_back* sback,httrackp* opt,cache_back* cache,lien_url** liens,int ptr,int numero_passe,int lien_tot) {
  2844.   if (!opt->state.stop) {
  2845.     if (back_incache(sback)<opt->maxcache) {  // pas trop en mΘmoire?
  2846.       return back_fill(sback,opt,cache,liens,ptr,numero_passe,lien_tot);
  2847.     }
  2848.   }
  2849.   return -1;                /* plus de place */
  2850. }
  2851.  
  2852. int back_pluggable_sockets_strict(struct_back* sback, httrackp* opt) {
  2853.   int n = opt->maxsoc - back_nsoc(sback);
  2854.  
  2855.   // connect limiter
  2856.   if (n > 0 && opt->maxconn > 0 && HTS_STAT.last_connect > 0) {
  2857.     TStamp opTime = HTS_STAT.last_request ? HTS_STAT.last_request : HTS_STAT.last_connect;
  2858.     TStamp cTime = mtime_local();
  2859.     TStamp lap = ( cTime - opTime );
  2860.     TStamp minLap = (TStamp) ( 1000.0 / opt->maxconn );
  2861.     if (lap < minLap) {
  2862.       n = 0;
  2863.     } else {
  2864.       int nMax = (int) ( lap / minLap );
  2865.       n = min(n, nMax);
  2866.     }
  2867.   }
  2868.  
  2869.   return n;
  2870. }
  2871.  
  2872. int back_pluggable_sockets(struct_back* sback, httrackp* opt) {
  2873.   int n;
  2874.  
  2875.   // ajouter autant de socket qu'on peut ajouter
  2876.   n=back_pluggable_sockets_strict(sback, opt);
  2877.  
  2878.   // vΘrifier qu'il restera assez de place pour les tests ensuite (en thΘorie, 1 entrΘe libre restante suffirait)
  2879.   n=min( n, back_available(sback) - 8 );
  2880.  
  2881.   // no space left on backing stack - do not back anymore
  2882.   if (back_stack_available(sback) <= 2)
  2883.     n=0;
  2884.  
  2885.   return n;
  2886. }
  2887.  
  2888. // remplir backing
  2889. int back_fill(struct_back* sback,httrackp* opt,cache_back* cache,lien_url** liens,int ptr,int numero_passe,int lien_tot) {
  2890.   int n = back_pluggable_sockets(sback, opt);
  2891.   if (opt->savename_delayed == 2 && !opt->delayed_cached)  /* cancel (always delayed) */
  2892.     return 0;
  2893.   if (n>0) {
  2894.     int p;
  2895.  
  2896.     if (ptr<cache->ptr_last) {      /* restart (2 scans: first html, then non html) */
  2897.       cache->ptr_ant=0;
  2898.     }
  2899.  
  2900.     p=ptr+1;
  2901.     /* on a dΘja parcouru */
  2902.     if (p<cache->ptr_ant)
  2903.       p=cache->ptr_ant;
  2904.     while( (p<lien_tot) && (n>0) && back_checkmirror(opt)) {
  2905.     //while((p<lien_tot) && (n>0) && (p < ptr+opt->maxcache_anticipate)) {
  2906.       int ok=1;
  2907.       
  2908.       // on ne met pas le fichier en backing si il doit Ωtre traitΘ aprΦs ou s'il a dΘja ΘtΘ traitΘ
  2909.       if (liens[p]->pass2) {  // 2Φ passe
  2910.         if (numero_passe!=1)
  2911.           ok=0;
  2912.       } else {
  2913.         if (numero_passe!=0)
  2914.           ok=0;
  2915.       }
  2916.       if (ok && liens[p]->sav != NULL && liens[p]->sav[0] != '\0' 
  2917.         && hash_read(opt->hash,liens[p]->sav,"",0,opt->urlhack) >= 0)     // lookup in liens_record
  2918.       {
  2919.         ok = 0;
  2920.       }
  2921.       
  2922.       // note: si un backing est fini, il reste en mΘmoire jusqu'α ce que
  2923.       // le ptr l'atteigne
  2924.       if (ok) {
  2925.         if (!back_exist(sback, opt, liens[p]->adr,liens[p]->fil,liens[p]->sav)) {
  2926.           if (back_add(sback,opt,cache,liens[p]->adr,liens[p]->fil,liens[p]->sav,liens[liens[p]->precedent]->adr,liens[liens[p]->precedent]->fil,liens[p]->testmode)==-1) {
  2927.             if ( (opt->debug>1) && (opt->log!=NULL) ) {
  2928.               HTS_LOG(opt,LOG_DEBUG); fprintf(opt->log,"error: unable to add more links through back_add for back_fill"LF);
  2929.               test_flush;
  2930.             }                    
  2931. #if BDEBUG==1
  2932.             printf("error while adding\n");
  2933. #endif                  
  2934.             n=0;    // sortir
  2935.           } else {
  2936.             n--;
  2937. #if BDEBUG==1
  2938.             printf("backing: %s%s\n",liens[p]->adr,liens[p]->fil);          
  2939. #endif
  2940.           } 
  2941.                 }
  2942.       }
  2943.       p++;
  2944.     }  // while
  2945.     /* sauver position derniΦre anticipation */
  2946.     cache->ptr_ant=p;
  2947.     cache->ptr_last=ptr;
  2948.   }
  2949.   return 0;
  2950. }
  2951. // ---
  2952.  
  2953.  
  2954.  
  2955.  
  2956.  
  2957.  
  2958.  
  2959.  
  2960.  
  2961.  
  2962.  
  2963.  
  2964.  
  2965.  
  2966.  
  2967.  
  2968.  
  2969.  
  2970. // Poll stdin.. si besoin
  2971. #if HTS_POLL
  2972. // lecture stdin des caractΦres disponibles
  2973. int read_stdin(char* s,int max) {
  2974.   int i=0;
  2975.   while((check_stdin()) && (i<(max-1)) )
  2976.     s[i++]=fgetc(stdin);
  2977.   s[i]='\0';
  2978.   return i;
  2979. }
  2980. #ifdef _WIN32
  2981. HTS_INLINE int check_stdin(void) {
  2982. #ifndef _WIN32_WCE
  2983.   return (_kbhit());
  2984. #else
  2985.   return 0;
  2986. #endif
  2987. }
  2988. #else
  2989. HTS_INLINE int check_flot(T_SOC s) {
  2990.   fd_set fds;
  2991.   struct timeval tv;
  2992.   FD_ZERO(&fds);
  2993.   FD_SET((T_SOC) s,&fds);
  2994.   tv.tv_sec=0;
  2995.   tv.tv_usec=0;
  2996.   select(s+1,&fds,NULL,NULL,&tv);
  2997.   return FD_ISSET(s,&fds);
  2998. }
  2999. HTS_INLINE int check_stdin(void) {
  3000.   fflush(stdout); fflush(stdin);
  3001.   if (check_flot(0))
  3002.     return 1;
  3003.   return 0;
  3004. }
  3005. #endif
  3006. #endif
  3007.  
  3008. HTS_INLINE int check_sockerror(T_SOC s) {
  3009.   fd_set fds;
  3010.   struct timeval tv;
  3011.   FD_ZERO(&fds);
  3012.   FD_SET((T_SOC) s,&fds);
  3013.   tv.tv_sec=0;
  3014.   tv.tv_usec=0;
  3015.   select(s+1,NULL,NULL,&fds,&tv);
  3016.   return FD_ISSET(s,&fds);
  3017. }
  3018.  
  3019. /* check incoming data */
  3020. HTS_INLINE int check_sockdata(T_SOC s) {
  3021.   fd_set fds;
  3022.   struct timeval tv;
  3023.   FD_ZERO(&fds);
  3024.   FD_SET((T_SOC) s,&fds);
  3025.   tv.tv_sec=0;
  3026.   tv.tv_usec=0;
  3027.   select(s+1,&fds,NULL,NULL,&tv);
  3028.   return FD_ISSET(s,&fds);
  3029. }
  3030.  
  3031. // Attente de touche
  3032. int ask_continue(httrackp *opt) {
  3033.   const char* s;
  3034.   s = RUN_CALLBACK1(opt, query2, opt->state.HTbuff);
  3035.   if (s) {
  3036.     if (strnotempty(s)) {
  3037.       if ((strfield2(s,"N")) || (strfield2(s,"NO")) || (strfield2(s,"NON")))
  3038.         return 0;
  3039.     }
  3040.     return 1;
  3041.   }
  3042.   return 1;
  3043. }
  3044.  
  3045. // nombre de digits dans un nombre
  3046. int nombre_digit(int n) {
  3047.   int i=1;
  3048.   while(n >= 10) { n/=10; i++; }
  3049.   return i;
  3050. }
  3051.  
  3052.  
  3053. // renvoi adresse de la fin du token dans p
  3054. // renvoi NULL si la chaine est un token unique
  3055. // (PATCHE Θgalement la chaine)
  3056. // ex: "test" "test2" renvoi adresse sur espace
  3057. // flag==1 si chaine comporte des echappements comme \"
  3058. char* next_token(char* p,int flag) {
  3059.   int detect=0;
  3060.   int quote=0;
  3061.   p--;
  3062.   do {
  3063.     p++;
  3064.     if (flag && (*p=='\\')) {   // sauter \x ou \"
  3065.       if (quote) {
  3066.         char c='\0';
  3067.         if (*(p+1)=='\\')
  3068.           c='\\';
  3069.         else if (*(p+1)=='"')
  3070.           c='"';
  3071.         if (c) {
  3072.           char BIGSTK tempo[8192];
  3073.           tempo[0]=c; tempo[1]='\0';
  3074.           strcatbuff(tempo,p+2);
  3075.           strcpybuff(p,tempo);
  3076.         }
  3077.       }
  3078.     }
  3079.     else if (*p==34) {  // guillemets (de fin)
  3080.       char BIGSTK tempo[8192];
  3081.       tempo[0]='\0';
  3082.       strcatbuff(tempo,p+1);
  3083.       strcpybuff(p,tempo);   /* wipe "" */
  3084.       p--;
  3085.       /* */
  3086.       quote=!quote;
  3087.     }
  3088.     else if (*p==32) {
  3089.       if (!quote)
  3090.         detect=1;
  3091.     }
  3092.     else if (*p=='\0') {
  3093.       p=NULL;
  3094.       detect=1;
  3095.     }
  3096.   } while(!detect);
  3097.   return p;
  3098. }
  3099.  
  3100. static int hts_cancel_file_push_(httrackp *opt, const char *url) {
  3101.   if (url != NULL && url[0] != '\0') {
  3102.     htsoptstatecancel **cancel;
  3103.     /* search for available place to store a new htsoptstatecancel* */
  3104.     for( cancel = &opt->state.cancel ; *cancel != NULL ; cancel = & ( (*cancel)->next ) ) {
  3105.       if (strcmp((*cancel)->url, url) == 0) {
  3106.         return 1;       /* already there */
  3107.       }
  3108.     }
  3109.     *cancel = malloct(sizeof(htsoptstatecancel));
  3110.     (*cancel)->next = NULL;
  3111.     (*cancel)->url = strdupt(url);
  3112.     return 0;
  3113.   }
  3114.   return 1;
  3115. }
  3116.  
  3117. /* cancel a file (locked) */
  3118. HTSEXT_API int hts_cancel_file_push(httrackp *opt, const char *url) {
  3119.   int ret;
  3120.   hts_mutexlock(&opt->state.lock);
  3121.   ret = hts_cancel_file_push_(opt, url);
  3122.   hts_mutexrelease(&opt->state.lock);
  3123.   return ret;
  3124. }
  3125.  
  3126. static char* hts_cancel_file_pop_(httrackp *opt) {
  3127.   if (opt->state.cancel != NULL) {
  3128.     htsoptstatecancel **cancel;
  3129.     htsoptstatecancel *ret;
  3130.     for( cancel = &opt->state.cancel ; (*cancel)->next != NULL ; cancel = & ( (*cancel)->next ) );
  3131.     ret = *cancel;
  3132.     *cancel = NULL;
  3133.     return ret->url;
  3134.   }
  3135.   return NULL;    /* no entry */
  3136. }
  3137.  
  3138. char* hts_cancel_file_pop(httrackp *opt) {
  3139.   char* ret;
  3140.   hts_mutexlock(&opt->state.lock);
  3141.   ret = hts_cancel_file_pop_(opt);
  3142.   hts_mutexrelease(&opt->state.lock);
  3143.   return ret;
  3144. }
  3145.  
  3146. HTSEXT_API void hts_cancel_test(httrackp *opt) {
  3147.   if (opt->state._hts_in_html_parsing==2)
  3148.     opt->state._hts_cancel=2;
  3149. }
  3150. HTSEXT_API void hts_cancel_parsing(httrackp *opt) {
  3151.   if (opt->state._hts_in_html_parsing)
  3152.     opt->state._hts_cancel=1;
  3153. }
  3154.  
  3155. // en train de parser un fichier html? rΘponse: % effectuΘs
  3156. // flag>0 : refresh demandΘ
  3157. HTSEXT_API int hts_is_parsing(httrackp *opt, int flag) {
  3158.   if (opt->state._hts_in_html_parsing) {  // parsing?
  3159.     if (flag >= 0)
  3160.             opt->state._hts_in_html_poll = 1;  // faudrait un tit refresh
  3161.     return max(opt->state._hts_in_html_done, 1); // % effectuΘs
  3162.   } else {
  3163.     return 0;                 // non
  3164.   }
  3165. }
  3166. HTSEXT_API int hts_is_testing(httrackp *opt) {            // 0 non 1 test 2 purge
  3167.   if (opt->state._hts_in_html_parsing==2)
  3168.     return 1;
  3169.   else if (opt->state._hts_in_html_parsing==3)
  3170.     return 2;
  3171.   else if (opt->state._hts_in_html_parsing==4)
  3172.     return 3;
  3173.   else if (opt->state._hts_in_html_parsing==5)   // scheduling
  3174.     return 4;
  3175.   else if (opt->state._hts_in_html_parsing==6)   // wait for slot
  3176.     return 5;
  3177.   return 0;
  3178. }
  3179. HTSEXT_API int hts_is_exiting(httrackp *opt) {
  3180.   return opt->state.exit_xh;
  3181. }
  3182. // message d'erreur?
  3183. char* hts_errmsg(httrackp *opt) {
  3184.   return opt->state._hts_errmsg;
  3185. }
  3186. // mode pause transfer
  3187. HTSEXT_API int hts_setpause(httrackp *opt, int p) {
  3188.   if (p >= 0)
  3189.         opt->state._hts_setpause = p;
  3190.   return opt->state._hts_setpause;
  3191. }
  3192. // ask for termination
  3193. HTSEXT_API int hts_request_stop(httrackp* opt, int force) {
  3194.   if (opt != NULL) {
  3195.     opt->state.stop = 1;
  3196.   }
  3197.   return 0;
  3198. }
  3199. // rΘgler en cours de route les paramΦtres rΘglables..
  3200. // -1 : erreur
  3201. //HTSEXT_API int hts_setopt(httrackp* set_opt) {
  3202. //  if (set_opt) {
  3203. //    httrackp* engine_opt=hts_declareoptbuffer(NULL);
  3204. //    if (engine_opt) {
  3205. //      //_hts_setopt=opt;
  3206. //      copy_htsopt(set_opt,engine_opt);
  3207. //    }
  3208. //  }
  3209. //  return 0;
  3210. //}
  3211. // ajout d'URL
  3212. // -1 : erreur
  3213. HTSEXT_API int hts_addurl(httrackp *opt, char** url) {
  3214.   if (url)
  3215.         opt->state._hts_addurl = url;
  3216.   return (opt->state._hts_addurl != NULL);
  3217. }
  3218. HTSEXT_API int hts_resetaddurl(httrackp *opt) {
  3219.   opt->state._hts_addurl = NULL;
  3220.   return (opt->state._hts_addurl != NULL);
  3221. }
  3222. // copier nouveaux paramΦtres si besoin
  3223. HTSEXT_API int copy_htsopt(const httrackp* from,httrackp* to) {
  3224.   if (from->maxsite > -1) 
  3225.     to->maxsite = from->maxsite;
  3226.   
  3227.   if (from->maxfile_nonhtml > -1) 
  3228.     to->maxfile_nonhtml = from->maxfile_nonhtml;
  3229.   
  3230.   if (from->maxfile_html > -1) 
  3231.     to->maxfile_html = from->maxfile_html;
  3232.   
  3233.   if (from->maxsoc > 0) 
  3234.     to->maxsoc = from->maxsoc;
  3235.   
  3236.   if (from->nearlink > -1) 
  3237.     to->nearlink = from->nearlink;
  3238.   
  3239.   if (from->timeout > -1) 
  3240.     to->timeout = from->timeout;
  3241.   
  3242.   if (from->rateout > -1)
  3243.     to->rateout = from->rateout;
  3244.   
  3245.   if (from->maxtime > -1) 
  3246.     to->maxtime = from->maxtime;
  3247.  
  3248. #if HTS_USEMMS
  3249.     if (from->mms_maxtime > -1)
  3250.     to->mms_maxtime = from->mms_maxtime;
  3251. #endif
  3252.  
  3253.   if (from->maxrate > -1)
  3254.     to->maxrate = from->maxrate;
  3255.   
  3256.   if (from->maxconn > 0)
  3257.     to->maxconn = from->maxconn;
  3258.  
  3259.   if (StringNotEmpty(from->user_agent)) 
  3260.     StringCopyS(to->user_agent, from->user_agent);
  3261.   
  3262.   if (from->retry > -1) 
  3263.     to->retry = from->retry;
  3264.   
  3265.   if (from->hostcontrol > -1) 
  3266.     to->hostcontrol = from->hostcontrol;
  3267.   
  3268.   if (from->errpage > -1) 
  3269.     to->errpage = from->errpage;
  3270.  
  3271.   if (from->parseall > -1) 
  3272.     to->parseall = from->parseall;
  3273.  
  3274.  
  3275.   // test all: bit 8 de travel
  3276.   if (from->travel > -1)  {
  3277.     if (from->travel & 256)
  3278.       to->travel|=256;
  3279.     else
  3280.       to->travel&=255;
  3281.   }
  3282.  
  3283.  
  3284.   return 0;
  3285. }
  3286.  
  3287. //
  3288.  
  3289. /* External modules callback */
  3290. int htsAddLink(htsmoduleStruct* str, char* link) {
  3291.   if (link != NULL && str != NULL && link[0] != '\0') {
  3292.     ENGINE_LOAD_CONTEXT_BASE();
  3293.     /* */
  3294.     char BIGSTK adr[HTS_URLMAXSIZE*2],
  3295.       fil[HTS_URLMAXSIZE*2],
  3296.       save[HTS_URLMAXSIZE*2];
  3297.     char BIGSTK codebase[HTS_URLMAXSIZE*2];
  3298.     /* */
  3299.     int pass_fix, prio_fix;
  3300.     /* */
  3301.     int forbidden_url = 1;
  3302.     
  3303.     codebase[0]='\0';
  3304.     
  3305.     if ((opt->debug>1) && (opt->log!=NULL)) {
  3306.       HTS_LOG(opt,LOG_DEBUG); fprintf(opt->log,"(module): adding link : '%s'"LF, link); test_flush;
  3307.     }
  3308.     // recopie de "creer le lien"
  3309.     //    
  3310.  
  3311.     if (!RUN_CALLBACK1(opt, linkdetected, link)) {
  3312.       if (opt->log) {
  3313.         HTS_LOG(opt,LOG_ERROR); fprintf(opt->log,"Link %s refused by external wrapper"LF, link);
  3314.         test_flush;
  3315.       }
  3316.       return 0;
  3317.     }
  3318.     if (!RUN_CALLBACK2(opt, linkdetected2, link, NULL)) {
  3319.       if (opt->log) {
  3320.         HTS_LOG(opt,LOG_ERROR); fprintf(opt->log,"Link %s refused by external wrapper(2)"LF, link);
  3321.         test_flush;
  3322.       }
  3323.       return 0;
  3324.     }
  3325.  
  3326.     // adr = c'est la mΩme
  3327.     // fil et save: save2 et fil2
  3328.     prio_fix=maximum(liens[ptr]->depth-1,0);
  3329.     pass_fix=max(liens[ptr]->pass2,numero_passe);
  3330.     if (liens[ptr]->cod) strcpybuff(codebase,liens[ptr]->cod);       // codebase valable pour tt les classes descendantes
  3331.     if (strnotempty(codebase)==0) {    // pas de codebase, construire
  3332.       char* a;
  3333.       if (str->relativeToHtmlLink == 0)
  3334.         strcpybuff(codebase,liens[ptr]->fil);
  3335.       else
  3336.         strcpybuff(codebase,liens[liens[ptr]->precedent]->fil);
  3337.       a=codebase+strlen(codebase)-1;
  3338.       while((*a) && (*a!='/') && ( a > codebase)) a--;
  3339.       if (*a=='/')
  3340.         *(a+1)='\0';    // couper
  3341.     } else {    // couper http:// Θventuel
  3342.       if (strfield(codebase,"http://")) {
  3343.         char BIGSTK tempo[HTS_URLMAXSIZE*2];
  3344.         char* a=codebase+7;
  3345.         a=strchr(a,'/');    // aprΦs host
  3346.         if (a) {  // ** msg erreur et vΘrifier?
  3347.           strcpybuff(tempo,a);
  3348.           strcpybuff(codebase,tempo);    // couper host
  3349.         } else {
  3350.           if (opt->log) {   
  3351.             fprintf(opt->log,"Unexpected strstr error in base %s"LF,codebase);
  3352.             test_flush;
  3353.           }
  3354.         }
  3355.       }
  3356.     }
  3357.     
  3358.     if (!((int) strlen(codebase)<HTS_URLMAXSIZE)) {    // trop long
  3359.       if (opt->log) {   
  3360.         fprintf(opt->log,"Codebase too long, parsing skipped (%s)"LF,codebase);
  3361.         test_flush;
  3362.       }
  3363.     }
  3364.     
  3365.     {
  3366.       char* lien = link;
  3367.       int dejafait=0;
  3368.       
  3369.       if (strnotempty(lien) && strlen(lien) < HTS_URLMAXSIZE) {
  3370.         
  3371.         // calculer les chemins et noms de sauvegarde
  3372.         if (ident_url_relatif(lien,urladr,codebase,adr,fil)>=0) { // reformage selon chemin
  3373.           int r;
  3374.           int set_prio_to = 0;
  3375.           int just_test_it = 0;
  3376.           forbidden_url = hts_acceptlink(opt, ptr, lien_tot, liens,
  3377.             adr,fil,
  3378.             NULL, NULL,
  3379.             &set_prio_to,
  3380.             &just_test_it);
  3381.           if ((opt->debug>1) && (opt->log!=NULL)) {
  3382.             HTS_LOG(opt,LOG_DEBUG); fprintf(opt->log,"result for wizard external module link: %d"LF,forbidden_url);
  3383.             test_flush;
  3384.           }
  3385.  
  3386.           /* Link accepted */
  3387.           if (!forbidden_url) {
  3388.             char BIGSTK tempo[HTS_URLMAXSIZE*2];
  3389.             int a,b;
  3390.             tempo[0]='\0';
  3391.             a=opt->savename_type;
  3392.             b=opt->savename_83;
  3393.             opt->savename_type=0;
  3394.             opt->savename_83=0;
  3395.             // note: adr,fil peuvent Ωtre patchΘs
  3396.             r=url_savename(adr,fil,save,NULL,NULL,NULL,NULL,opt,liens,lien_tot,sback,cache,hashptr,ptr,numero_passe,NULL);
  3397.             // resolve unresolved type
  3398.             if (r != -1
  3399.               && forbidden_url == 0
  3400.               && IS_DELAYED_EXT(save)
  3401.               ) 
  3402.             {  // pas d'erreur, on continue
  3403.               char BIGSTK former_adr[HTS_URLMAXSIZE*2];
  3404.               char BIGSTK former_fil[HTS_URLMAXSIZE*2];
  3405.               former_adr[0] = former_fil[0] = '\0';
  3406.               r = hts_wait_delayed(str, adr, fil, save, NULL, NULL, former_adr, former_fil, &forbidden_url);
  3407.             }
  3408.             // end resolve unresolved type
  3409.             opt->savename_type=a;
  3410.             opt->savename_83=b;
  3411.             if (r != -1 && !forbidden_url) {
  3412.               if (savename) {
  3413.                 if (lienrelatif(tempo,save,savename)==0) {
  3414.                   if ((opt->debug>1) && (opt->log!=NULL)) {
  3415.                     HTS_LOG(opt,LOG_DEBUG); fprintf(opt->log,"(module): relative link at %s build with %s and %s: %s"LF,adr,save,savename,tempo);
  3416.                     test_flush;
  3417.                     if (str->localLink && str->localLinkSize > (int) strlen(tempo) + 1) {
  3418.                       strcpybuff(str->localLink, tempo);
  3419.                     }
  3420.                   }
  3421.                 }
  3422.               }
  3423.             }
  3424.           }
  3425.  
  3426.           if (forbidden_url) {
  3427.             if ((opt->debug>1) && (opt->log!=NULL)) {
  3428.               HTS_LOG(opt,LOG_DEBUG); fprintf(opt->log,"(module): file not caught: %s"LF,lien); test_flush;
  3429.             }
  3430.             if (str->localLink && str->localLinkSize > (int) ( strlen(adr) + strlen(fil) +  8 ) ) {
  3431.               str->localLink[0] = '\0';
  3432.               if (!link_has_authority(adr))
  3433.                 strcpybuff(str->localLink,"http://");
  3434.               strcatbuff(str->localLink, adr);
  3435.               strcatbuff(str->localLink, fil);
  3436.             }
  3437.             r=-1;
  3438.           }
  3439.  
  3440.           //
  3441.           if (r != -1) {
  3442.             if ((opt->debug>1) && (opt->log!=NULL)) {
  3443.               HTS_LOG(opt,LOG_DEBUG); fprintf(opt->log,"(module): %s%s -> %s (base %s)"LF,adr,fil,save,codebase); test_flush;
  3444.             }
  3445.             
  3446.             // modifiΘ par rapport α l'autre version (cf prio_fix notamment et save2)
  3447.             
  3448.             // vΘrifier que le lien n'a pas dΘja ΘtΘ notΘ
  3449.             // si c'est le cas, alors il faut s'assurer que la prioritΘ associΘe
  3450.             // au fichier est la plus grande des deux prioritΘs
  3451.             //
  3452.             // On part de la fin et on essaye de se presser (Θconomise temps machine)
  3453.             {
  3454.               int i=hash_read(hashptr,save,"",0,opt->urlhack);      // lecture type 0 (sav)
  3455.               if (i>=0) {
  3456.                 liens[i]->depth=maximum(liens[i]->depth,prio_fix);
  3457.                 dejafait=1;
  3458.               }
  3459.             }         
  3460.             
  3461.             if (!dejafait) {
  3462.               //
  3463.               // >>>> CREER LE LIEN JAVA <<<<
  3464.               
  3465.               // enregistrer fichier (MACRO)
  3466.               liens_record(adr,fil,save,"","",opt->urlhack);
  3467.               if (liens[lien_tot]==NULL) {  // erreur, pas de place rΘservΘe
  3468.                 printf("PANIC! : Not enough memory [%d]\n",__LINE__);
  3469.                 if (opt->log) { 
  3470.                   fprintf(opt->log,"Not enough memory, can not re-allocate %d bytes"LF,(int)((add_tab_alloc+1)*sizeof(lien_url)));
  3471.                   test_flush;
  3472.                 }
  3473.                 opt->state.exit_xh=-1;    /* fatal error -> exit */
  3474.                 return 0;
  3475.               }  
  3476.               
  3477.               // mode test?                          
  3478.               liens[lien_tot]->testmode=0;          // pas mode test
  3479.               
  3480.               liens[lien_tot]->link_import=0;       // pas mode import
  3481.               
  3482.               // Θcrire autres paramΦtres de la structure-lien
  3483.               //if (meme_adresse)                                 
  3484.               liens[lien_tot]->premier=liens[ptr]->premier;
  3485.               //else    // sinon l'objet pΦre est le prΘcΘdent lui mΩme
  3486.               //  liens[lien_tot]->premier=ptr;
  3487.               
  3488.               liens[lien_tot]->precedent=ptr;
  3489.               // noter la prioritΘ
  3490.               if (!set_prio_to)
  3491.                 liens[lien_tot]->depth=prio_fix;
  3492.               else
  3493.                 liens[lien_tot]->depth=max(0,min(liens[ptr]->depth-1,set_prio_to-1));         // PRIORITE NULLE (catch page)
  3494.               liens[lien_tot]->pass2=max(pass_fix,numero_passe);
  3495.               liens[lien_tot]->retry=opt->retry;
  3496.               
  3497.               //strcpybuff(liens[lien_tot]->adr,adr);
  3498.               //strcpybuff(liens[lien_tot]->fil,fil);
  3499.               //strcpybuff(liens[lien_tot]->sav,save); 
  3500.               if ((opt->debug>1) && (opt->log!=NULL)) {
  3501.                 HTS_LOG(opt,LOG_DEBUG); fprintf(opt->log,"(module): OK, NOTE: %s%s -> %s"LF,liens[lien_tot]->adr,liens[lien_tot]->fil,liens[lien_tot]->sav);
  3502.                 test_flush;
  3503.               }
  3504.               
  3505.               lien_tot++;  // UN LIEN DE PLUS
  3506.             }
  3507.           }
  3508.         }
  3509.       }
  3510.     }
  3511.     
  3512.     /* Apply changes */
  3513.     ENGINE_SAVE_CONTEXT_BASE();
  3514.  
  3515.     return (forbidden_url == 0);
  3516.   }
  3517.   return 0;
  3518. }
  3519.  
  3520.  
  3521.  
  3522.  
  3523.  
  3524. // message copyright interne
  3525. void voidf(void) {
  3526.   char* a;
  3527.   a=""CRLF""CRLF;
  3528.   a="+-----------------------------------------------+"CRLF;
  3529.   a="|HyperTextTRACKer, Offline Browser Utility      |"CRLF;
  3530.   a="|                      HTTrack Website Copier   |"CRLF;
  3531.   a="|Code:         Windows Interface Xavier Roche   |"CRLF;
  3532.   a="|                    HTS/HTTrack Xavier Roche   |"CRLF;
  3533.   a="|                .class Parser Yann Philippot   |"CRLF;
  3534.   a="|                                               |"CRLF;
  3535.   a="|Tested on:                 Windows95,98,NT,2K  |"CRLF;
  3536.   a="|                           Linux PC            |"CRLF;
  3537.   a="|                           Sun-Solaris 5.6     |"CRLF;
  3538.   a="|                           AIX 4               |"CRLF;
  3539.   a="|                                               |"CRLF;
  3540.   a="|Copyright (C) Xavier Roche and other           |"CRLF;
  3541.   a="|contributors                                   |"CRLF;
  3542.   a="|                                               |"CRLF;
  3543.   a="|Use this program at your own risks!            |"CRLF;    
  3544.   a="+-----------------------------------------------+"CRLF;
  3545.   a=""CRLF;
  3546. }
  3547.  
  3548.  
  3549. // HTTrack Website Copier Copyright (C) Xavier Roche and other contributors
  3550. //
  3551.  
  3552.